Tegevuse iseloomu tÔttu tuleb ette olukordi, kus arendaja kirjutab pÀringu ja mÔtleb: "andmebaas on nutikas, lahendab kÔik ise!"«
MÔnel juhul (osaliselt teadmatusest andmebaasi vÔimalustest, osaliselt liigsete varajaste optimeerimiste tÔttu) viib selline lÀhenemine "frankensteini" loomisele.
Alustuseks toome nÀite sellisest pÀringust:
-- iga vÔtme paari jaoks leiame seotud vÀljade 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Ôtme 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 jÀrgi 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 hindamiseks loome tĂŒĂŒpilise andmestiku kogumi:
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Àitmisest: Eurekala:

LÀbime pÔhjalikult
Vaadates pÀringut lÀhemalt, jÀÀme mÔtlema:
- Miks on siin WITH RECURSIVE, kui mingit rekurssiivset CTE-d â ei ole?
- Miks grupeerida min/max vÀÀrtused eraldi CTE-s, kui nad siis ikkagi seotakse originaalvalikuga?
+25% aega - Miks kasutada lĂ”pus uuesti eelmist CTE-d tingimusteta âSELECT * FROMâ kaudu?
+14% aega
Meil oli sel juhul eriti vedanud, et ĂŒhenduseks valiti Hash Join, mitte Nested Loop, sest muidu saaksime mitte ĂŒhte, vaid 10K lĂ€bitud CTE skaneeringut!
natuke CTE skaneerimisestSiin tuleb meeles pidada, et CTE skaneerimine on Seq skaneerimise analoog â see tĂ€hendab, et mingit indekseerimist ei ole, vaid tĂ€ielik lĂ€bitöötamine, mis nĂ”uab 10K x 0.3ms = 3000ms cte_max-i silmade kaudu vĂ”i 1K x 1.5ms = 1500ms cte_bind-i silmade kaudu!
Tegelikult, mida me tulemuseks tahtsime? Jah, tavaliselt selline kĂŒsimus tekib kusagil viienda minuti jooksul "kolmeastmeliste" pĂ€ringute analĂŒĂŒsimisel.
Soovisime igale unikaalsele vÔtme paarile esitada min/max grupi jÀrgi key_a.
Nii et 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, siis on kogu meie aja sÀÀst -32% â puhtalt koormus, mis on eemaldatud CPU pĂ”hilt, kui sellist pĂ€ringut tehakse piisavalt tihti.
Ăldiselt ei tasu baasi sundida "ĂŒmmargust kandma, kandilist veeretama".
Allikas: habr.com
