Minħabba l-linja tax-xogħol tiegħi, għandi nittratta sitwazzjonijiet meta żviluppatur jikteb talba u jaħseb "Il-bażi hija intelliġenti, tista 'timmaniġġja kollox innifsu!«
F'xi każijiet (parzjalment mill-injoranza tal-kapaċitajiet tad-database, parzjalment minn ottimizzazzjonijiet prematuri), dan l-approċċ iwassal għad-dehra ta '"Frankensteins".
L-ewwel, ser nagħti eżempju ta 'tali talba:
-- для каждой ключевой пары находим ассоциированные значения полей
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
)
-- находим min/max значений для каждого первого ключа
, cte_max AS (
SELECT
a
, max(bind_fld1) bind_fld1
, min(bind_fld2) bind_fld2
FROM
cte_bind
GROUP BY
a
)
-- связываем по первому ключу ключевые пары и min/max-значения
, 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;
Biex tevalwa b'mod sostantiv il-kwalità ta' talba, ejja noħolqu xi sett ta' data arbitrarju:
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);
Jirriżulta li il-qari tad-dejta ħa inqas minn kwart tal-ħin eżekuzzjoni tal-mistoqsija:
Teħodha barra biċċa biċċa
Ejja nagħtu ħarsa aktar mill-qrib lejn it-talba u nkunu mħawda:
- Għaliex hawn WITH RECURSIVE jekk m'hemmx CTEs rikorsivi?
- Għaliex jiġbor il-valuri min/max f'CTE separat jekk imbagħad ikunu marbuta mal-kampjun oriġinali xorta waħda?
+ 25% ħin - Għaliex tuża 'SELECT * FROM' bla kundizzjoni fl-aħħar biex tirrepeti s-CTE preċedenti?
+ 14% ħin
F'dan il-każ, konna xxurtjati ħafna li l-Hash Join intgħażel għall-konnessjoni, u mhux Nested Loop, għax allura konna nirċievu mhux pass wieħed biss ta 'CTE Scan, iżda 10K!
ftit dwar CTE ScanHawnhekk irridu niftakru li CTE Scan huwa simili għal Seq Scan - jiġifieri, l-ebda indiċjar, iżda biss tfittxija sħiħa, li tkun teħtieġ 10K x 0.3ms = 3000ms għal ċikli minn cte_max jew 1K x 1.5ms = 1500ms meta looping minn cte_bind!
Fil-fatt, x'ridt tikseb bħala riżultat? Iva, normalment din hija l-mistoqsija li toħroġ x'imkien fil-5 minuta ta 'analiżi ta' mistoqsijiet ta '"tliet sulari".
Ridna noħorġu għal kull par ta 'ċwievet uniku min/max mill-grupp minn key_a.
Mela ejja nużawha għal dan
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);
Peress li l-qari tad-dejta fiż-żewġ għażliet jieħu l-istess bejn wieħed u ieħor 4-5ms, allura l-ħin kollu tagħna jiksbu -32% - dan huwa fil-forma pura tiegħu tagħbija mneħħija mis-CPU bażi, jekk tali talba tiġi esegwita spiss biżżejjed.
B'mod ġenerali, m'għandekx ġġiegħel il-bażi "ġġorr it-tond, irrombla l-kwadru."
Sors: www.habr.com