Tegevuse iseloomust tulenevalt tuleb ette olukordi, kus arendaja kirjutab pÀringu ja mÔtleb: "tabel on nutikas, ise lahendab kÔik!"«
MÔnel juhul (osaliselt teadmatusest andmebaasi vÔimaluste suhtes, osaliselt enneaegsetest optimeerimistest) viib selline lÀhenemine "frankensteini" loomisele.
Alustuseks toon nÀite sellisest pÀringust:
-- iga vÔtme paari jaoks leidke seotud vÀÀrtused
WITH RECURSIVE cte_bind AS (
SELECT DISTINCT ON (key_a, key_b)
key_a a
, key_b b
, fld1 bind_fld1
, fld2 bind_fld2
FROM
tbl
)
-- leiame iga esimese vÔti jaoks min/max vÀÀrtused
, cte_max AS (
SELECT
a
, max(bind_fld1) bind_fld1
, min(bind_fld2) bind_fld2
FROM
cte_bind
GROUP BY
a
)
-- seome esimese vÔtme pÔhjal vÔtme paarid ja min/max-vÀÀrtused
, cte_a_bind AS (
SELECT
cte_bind.a
, cte_bind.b
, cte_max.bind_fld1
, cte_max.bind_fld2
FROM
cte_bind
INNER JOIN
cte_max
ON cte_max.a = cte_bind.a
)
SELECT * FROM cte_a_bind;Kvaliteedi objektiivseks hindamiseks loome mingisuguse meelevaldse andmestiku komplekti:
CREATE TABLE tbl AS
SELECT
(random() * 1000)::integer key_a
, (random() * 1000)::integer key_b
, (random() * 10000)::integer fld1
, (random() * 10000)::integer fld2
FROM
generate_series(1, 10000);
CREATE INDEX ON tbl(key_a, key_b);
Selgub, et andmete lugemine vĂ”ttis vĂ€hem kui veerand kogu pĂ€ringu tĂ€itmise ajast: ĐČŃĐżĐŸĐ»ĐœĐ”ĐœĐžŃ Đ·Đ°ĐżŃĐŸŃа:

LÀbime pÔhjalikult
Vaata tÀhelepanelikult pÀringut ja mÔtleme:
- Miks on siin WITH RECURSIVE, kui mingeid rekursiivseid CTE-sid pole?
- Miks gruppeerida min/max vÀÀrtused eraldi CTE-s, kui need hiljem ikkagi seotakse originaalvalikuga?
+25% aega - Miks kasutada lĂ”pus korduvat lugemist eelmisest CTE-st tingimusteta âSELECT * FROMâ kaudu?
+14% aega
Selles olukorras vedas meid, et ĂŒhendamiseks valiti Hash Join, mitte Nested Loop, sest muidu oleksime saanud mitte ĂŒhe ainsa CTE skaneerimise, vaid 10K!
veidi CTE skaneerimisestSiin on oluline meeles pidada, et CTE skaneerimine on sama mis Seq Scan â see tĂ€hendab, et ei mingit indekseerimist, vaid ainult tĂ€ielik otsimine, mis nĂ”uaks 10K x 0.3ms = 3000ms cte_max tsĂŒklite puhul vĂ”i 1K x 1.5ms = 1500ms cte_bind tsĂŒklite puhul!
Kuidas, aga mida soovisime lĂ”puks saada? Ah, tavaliselt tekib selline kĂŒsimus kuskil viienda minuti jooksul «kolmeastmeliste» pĂ€ringute analĂŒĂŒsi kĂ€igus.
Soovisime iga unikaalse vĂ”tme paari jaoks vĂ€lja tuua min/max rĂŒhmas key_a jĂ€rgi.
Kasutame selleks :
SELECT DISTINCT ON(key_a, key_b)
key_a a
, key_b b
, max(fld1) OVER(w) bind_fld1
, min(fld2) OVER(w) bind_fld2
FROM
tbl
WINDOW
w AS (PARTITION BY key_a); 
Kuna andmete lugemine mĂ”lemas variandis kestab umbes 4-5 ms, on kogu meie ajavĂ”it -32% â puhas koormus, mis on eemaldatud CPU pĂ”hilt, kui selline pĂ€ring toimub piisavalt tihti.
Ăldiselt ei tohiks anda andmebaasi ĂŒlesanne "ĂŒmmargune â kanda, nurgeline â veeretada".
Allikas: habr.com
