ΠΡΠ΅Π΄ΠΈ Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΠΌΠ΅ΡΠ΅ΡΠ° β ΠΏΡΠ±Π»ΠΈΡΠ΅Π½ ΠΊΡΠΌ PostgreSQL.
ΠΡΠ΅Π· ΡΠΎΠ²Π° Π²ΡΠ΅ΠΌΠ΅ Π²Π΅ΡΠ΅ ΡΡΠ΅ Π³ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π»ΠΈ Π½Π°Π΄ 6000 ΠΏΡΡΠΈ, Π½ΠΎ Π΅Π΄Π½Π° ΠΎΡ ΡΠ΄ΠΎΠ±Π½ΠΈΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΈ Π²Π΅ΡΠΎΡΡΠ½ΠΎ Π΅ ΠΎΡΡΠ°Π½Π°Π»Π° Π½Π΅Π·Π°Π±Π΅Π»ΡΠ·Π°Π½Π° β ΡΠΎΠ²Π° ΡΠ° ΡΡΡΡΠΊΡΡΡΠ½ΠΈΡΠ΅ ΠΏΠΎΠ΄ΡΠΊΠ°Π·ΠΊΠΈ, ΠΊΠΎΠΈΡΠΎ ΠΈΠ·Π³Π»Π΅ΠΆΠ΄Π°Ρ ΠΏΡΠΈΠ±Π»ΠΈΠ·ΠΈΡΠ΅Π»Π½ΠΎ ΡΠ°ΠΊΠ°:

ΠΡΠΈΡΠ»ΡΡΠ²Π°ΠΉΡΠ΅ ΡΠ΅ ΠΊΡΠΌ ΡΡΡ
ΠΈ Π²Π°ΡΠΈΡΠ΅ Π·Π°ΡΠ²ΠΊΠΈ "ΡΠ΅ ΡΡΠ°Π½Π°Ρ Π³Π»Π°Π΄ΠΊΠΈ ΠΈ ΠΊΠΎΠΏΡΠΈΠ½Π΅Π½ΠΈ". π
Π Π°ΠΊΠΎ Π±ΡΠ΄Π΅ΠΌ ΡΠ΅ΡΠΈΠΎΠ·Π½ΠΈ, ΠΌΠ½ΠΎΠ³ΠΎ ΡΠΈΡΡΠ°ΡΠΈΠΈ, ΠΊΠΎΠΈΡΠΎ ΠΏΡΠ°Π²ΡΡ Π·Π°ΡΠ²ΠΊΠ°ΡΠ° Π±Π°Π²Π½Π° ΠΈ "Π³Π»Π°Π΄Π½Π°" Π·Π° ΡΠ΅ΡΡΡΡΠΈ, ΡΠ° ΡΠΈΠΏΠΈΡΠ½ΠΈ ΠΈ ΠΌΠΎΠ³Π°Ρ Π΄Π° Π±ΡΠ΄Π°Ρ ΡΠ°Π·ΠΏΠΎΠ·Π½Π°ΡΠΈ ΠΏΠΎ ΡΡΡΡΠΊΡΡΡΠ°ΡΠ° ΠΈ Π΄Π°Π½Π½ΠΈΡΠ΅ Π½Π° ΠΏΠ»Π°Π½Π°.
Π ΡΠΎΠ·ΠΈ ΡΠ»ΡΡΠ°ΠΉ Π²ΡΠ΅ΠΊΠΈ ΠΎΡΠ΄Π΅Π»Π΅Π½ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊ Π½ΡΠΌΠ° Π΄Π° ΡΡΡΠ±Π²Π° Π΄Π° ΡΡΡΡΠΈ Π²Π°ΡΠΈΠ°Π½Ρ Π·Π° ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΠ°ΠΌΠΎΡΡΠΎΡΡΠ΅Π»Π½ΠΎ, ΡΠ°Π·ΡΠΈΡΠ°ΠΉΠΊΠΈ Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½ΠΎ Π½Π° ΡΠ²ΠΎΡ ΠΎΠΏΠΈΡ β ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΌΡ ΠΏΠΎΠ΄ΡΠΊΠ°Π·Π²Π°ΠΌΠ΅ ΠΊΠ°ΠΊΠ²ΠΎ ΡΡΠ°Π²Π°, ΠΊΠ°ΠΊΠ²Π° ΠΌΠΎΠΆΠ΅ Π΄Π° Π±ΡΠ΄Π΅ ΠΏΡΠΈΡΠΈΠ½Π°ΡΠ° ΠΈ ΠΊΠ°ΠΊ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΠΈ ΠΊΡΠΌ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ΡΠΎ. ΠΠ°ΠΊΡΠΎ Π½Π°ΠΏΡΠ°Π²ΠΈΡ ΠΌΠ΅.

ΠΠ΅ΠΊΠ° Π΄Π° ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΌΠ΅ ΠΏΠΎ-ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ ΡΠ΅Π·ΠΈ ΡΠ»ΡΡΠ°ΠΈ β ΠΊΠ°ΠΊ ΡΠ΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΡ ΠΈ ΠΊΡΠΌ ΠΊΠ°ΠΊΠ²ΠΈ ΠΏΡΠ΅ΠΏΠΎΡΡΠΊΠΈ Π²ΠΎΠ΄ΡΡ.
ΠΠ° ΠΏΠΎ-Π΄ΠΎΠ±ΡΠΎ ΠΏΠΎΡΠ°ΠΏΡΠ½Π΅ Π² ΡΠ΅ΠΌΠ°ΡΠ° ΠΏΡΡΠ²ΠΎ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΡΡΠ΅ΡΠ΅ ΡΡΠΎΡΠ²Π΅ΡΠ½ΠΈΡ Π±Π»ΠΎΠΊ ΠΎΡ , Π° ΡΠ»Π΅Π΄ ΡΠΎΠ²Π° Π΄Π° ΠΏΡΠ΅ΠΌΠΈΠ½Π΅ΡΠ΅ ΠΊΡΠΌ Π΄Π΅ΡΠ°ΠΉΠ»Π½ΠΈΡ Π°Π½Π°Π»ΠΈΠ· Π½Π° Π²ΡΠ΅ΠΊΠΈ ΠΏΡΠΈΠΌΠ΅Ρ:

#1: ΠΈΠ½Π΄Π΅ΠΊΡΠ½Π°Ρ Β«Π½Π΅Π΄ΠΎΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠ°Β»
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
ΠΠΎΠΊΠ°ΠΆΠ΅ΡΠ΅ ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΡ ΠΎΡΡΠ΅Ρ Π·Π° ΠΊΠ»ΠΈΠ΅Π½ΡΠ° "ΠΠΠ ΠΠΎΠ»ΠΎΠΊΠΎΠ»ΡΡΠΈΠΊ".
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> Limit
-> Sort
-> Index [Only] Scan [Backward] | Bitmap Heap Scan
ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΈΡΡ ΠΈΠ½Π΄Π΅ΠΊΡ Π΄Π° ΡΠ΅ ΡΠ°Π·ΡΠΈΡΠΈ Ρ ΠΏΠΎΠ»Π΅ΡΠ° Π·Π° ΡΠΎΡΡΠΈΡΠ°Π½Π΅.
ΠΡΠΈΠΌΠ΅Ρ:
CREATE TABLE tbl AS
SELECT
generate_series(1, 100000) pk -- 100K "ΡΠ°ΠΊΡΠΈ"
, (random() * 1000)::integer fk_cli; -- 1K ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠΎΠ²Π΅
CREATE INDEX ON tbl(fk_cli); -- ΠΈΠ½Π΄Π΅ΠΊΡ Π·Π° foreign key
SELECT
*
FROM
tbl
WHERE
fk_cli = 1 -- ΠΏΠΎΠ΄Π±ΠΎΡ ΠΏΠΎ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½Π° Π²ΡΡΠ·ΠΊΠ°
ORDER BY
pk DESC -- ΠΈΡΠΊΠ°ΠΌΠ΅ ΡΠ°ΠΌΠΎ Π΅Π΄ΠΈΠ½ "ΠΏΠΎΡΠ»Π΅Π΄Π΅Π½" Π·Π°ΠΏΠΈΡ
LIMIT 1; 
ΠΠ΅Π΄Π½Π°Π³Π° Π΅ Π²ΠΈΠ΄Π½ΠΎ, ΡΠ΅ ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΠ° ΡΠ° ΠΈΠ·Π²Π°Π΄Π΅Π½ΠΈ Π½Π°Π΄ 100 Π·Π°ΠΏΠΈΡΠ°, ΠΊΠΎΠΈΡΠΎ ΡΠ»Π΅Π΄ ΡΠΎΠ²Π° ΡΠ° Π±ΠΈΠ»ΠΈ Π²ΡΠΈΡΠΊΠΈ ΡΠΎΡΡΠΈΡΠ°Π½ΠΈ, Π° ΡΠ»Π΅Π΄ ΡΠΎΠ²Π° Π΅ ΠΎΡΡΠ°Π½Π°Π» ΡΠ°ΠΌΠΎ Π΅Π΄ΠΈΠ½.
ΠΠΎΠΏΡΠ°Π²ΡΠΌΠ΅:
DROP INDEX tbl_fk_cli_idx;
CREATE INDEX ON tbl(fk_cli, pk DESC); -- Π΄ΠΎΠ±Π°Π²ΠΈΡ
ΠΌΠ΅ ΠΊΠ»ΡΡ Π·Π° ΡΠΎΡΡΠΈΡΠ°Π½Π΅

ΠΠΎΡΠΈ Π½Π° ΡΠ°ΠΊΠΎΠ²Π° ΠΏΡΠΎΡΡΠΈΡΠ½ΠΎ ΠΈΠ·Π²Π°Π΄ΠΊΠ° β 8.5 ΠΏΡΡΠΈ ΠΏΠΎ-Π±ΡΡΠ·ΠΎ ΠΈ Ρ 33 ΠΏΡΡΠΈ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΡ.ΠΡΠ΅ΠΊΡΡΡ ΡΠ΅ Π±ΡΠ΄Π΅ ΠΏΠΎ-ΠΎΡΠ΅Π²ΠΈΠ΄Π΅Π½, ΠΊΠΎΠ»ΠΊΠΎΡΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅ "ΡΠ°ΠΊΡΠΈ" ΠΈΠΌΠ°ΡΠ΅ Π·Π° Π²ΡΡΠΊΠΎ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ fk.
ΠΠ°Π±Π΅Π»ΡΠ·Π²Π°ΠΌ, ΡΠ΅ ΡΠ°ΠΊΡΠ² ΠΈΠ½Π΄Π΅ΠΊΡ ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈ ΠΊΠ°ΡΠΎ "ΠΏΡΠ΅ΡΠΈΠΊΡΠ΅Π½" Π½Π΅ ΠΏΠΎ-Π»ΠΎΡΠΎ ΠΎΡ ΠΏΡΠ΅Π΄ΠΈΡΠ½ΠΈΡ ΠΈ Π·Π° Π΄ΡΡΠ³ΠΈ Π·Π°ΡΠ²ΠΊΠΈ Ρ fk, ΠΊΡΠ΄Π΅ΡΠΎ ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠΈΡΠ΅ ΠΏΠΎ pk Π½Π΅ Π΅ ΠΈΠΌΠ°Π»ΠΎ ΠΈ Π½ΡΠΌΠ° (ΠΏΠΎΠ²Π΅ΡΠ΅ Π·Π° ΡΠΎΠ²Π° ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° ΠΏΡΠΎΡΠ΅ΡΠ΅ΡΠ΅ ). ΠΠΊΠ»ΡΡΠΈΡΠ΅Π»Π½ΠΎ, ΡΠΎΠΉ ΡΠ΅ ΠΎΡΠΈΠ³ΡΡΠΈ ΠΈ Π½ΠΎΡΠΌΠ°Π»Π½Π° ΠΏΠΎΠ΄Π΄ΡΡΠΆΠΊΠ° Π½Π° ΡΠ²Π΅Π½ foreign key ΠΏΠΎ ΡΠΎΠ²Π° ΠΏΠΎΠ»Π΅.
#2: ΠΏΠ΅ΡΠ΅ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΠΎΠ² (BitmapAnd)
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
ΠΠΎΠΊΠ°ΠΆΠ΅ΡΠ΅ Π²ΡΠΈΡΠΊΠΈ Π΄ΠΎΠ³ΠΎΠ²ΠΎΡΠΈ Π·Π° ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Β«ΠΠΠ ΠΠΎΠ»ΠΎΠΊΠΎΠ»ΡΡΠΈΠΊΒ», ΡΠΊΠ»ΡΡΠ΅Π½ΠΈ ΠΎΡ ΠΈΠΌΠ΅ΡΠΎ Π½Π° Β«ΠΠΠ ΠΡΡΠΈΠΊΒ».
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> BitmapAnd
-> Bitmap Index Scan
-> Bitmap Index ScanΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
Π‘ΡΠ·Π΄Π°Π²Π°Π½Π΅ ΡΡΡΡΠ°Π²Π΅Π½ ΠΈΠ½Π΄Π΅ΠΊΡ ΠΏΠΎ ΠΏΠΎΠ»Π΅ΡΠ°ΡΠ° ΠΎΡ ΠΈ Π΄Π²Π΅ΡΠ΅ ΠΈΠ·Ρ ΠΎΠ΄Π½ΠΈ, ΠΈΠ»ΠΈ ΡΠ°Π·ΡΠΈΡΠ΅ΡΠ΅ Π΅Π΄Π½ΠΎ ΠΎΡ ΡΡΡΠ΅ΡΡΠ²ΡΠ²Π°ΡΠΈΡΠ΅ Ρ ΠΏΠΎΠ»Π΅ΡΠ° ΠΎΡ Π²ΡΠΎΡΠΎΡΠΎ.
ΠΡΠΈΠΌΠ΅Ρ:
CREATE TABLE tbl AS
SELECT
generate_series(1, 100000) pk -- 100K "ΡΠ°ΠΊΡΠΈ"
, (random() * 100)::integer fk_org -- 100 ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠΎΠ²Π΅
, (random() * 1000)::integer fk_cli; -- 1K ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠΎΠ²Π΅
CREATE INDEX ON tbl(fk_org); -- ΠΈΠ½Π΄Π΅ΠΊΡ Π·Π° foreign key
CREATE INDEX ON tbl(fk_cli); -- ΠΈΠ½Π΄Π΅ΠΊΡ Π·Π° foreign key
SELECT
*
FROM
tbl
WHERE
(fk_org, fk_cli) = (1, 999); -- ΠΎΡΠ±ΠΎΡ ΠΏΠΎ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½Π° Π΄Π²ΠΎΠΉΠΊΠ° 
ΠΠΎΠΏΡΠ°Π²ΡΠΌΠ΅:
DROP INDEX tbl_fk_org_idx;
CREATE INDEX ON tbl(fk_org, fk_cli);

Π’ΡΠΊ ΠΏΠ΅ΡΠ°Π»Π±Π°ΡΠ° Π΅ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ, ΡΡΠΉ ΠΊΠ°ΡΠΎ Bitmap Heap Scan Π΅ Π΄ΠΎΡΡΠ°ΡΡΡΠ½ΠΎ Π΅ΡΠ΅ΠΊΡΠΈΠ²Π΅Π½ ΡΠ°ΠΌ ΠΏΠΎ ΡΠ΅Π±Π΅ ΡΠΈ. ΠΠΎ Π²ΡΠ΅ ΠΏΠ°ΠΊ Π² 7 ΠΏΡΡΠΈ ΠΏΠΎ-Π±ΡΡΠ·ΠΎ ΠΈ Ρ 2.5 ΠΏΡΡΠΈ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΡ.
#3: ΠΎΠ±ΡΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΠΎΠ² (BitmapOr)
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
ΠΠΎΠΊΠ°ΠΆΠ΅ΡΠ΅ ΠΏΡΡΠ²ΠΈΡΠ΅ 20 Π½Π°ΠΉ-ΡΡΠ°ΡΠΈ Β«ΡΠ²ΠΎΠΈΒ» ΠΈΠ»ΠΈ Π½Π΅Π½Π°ΡΠΎΡΠ΅Π½ΠΈ Π·Π°ΡΠ²ΠΊΠΈ Π·Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ°, ΠΊΠ°ΡΠΎ ΡΠ²ΠΎΠΈ Π² ΠΏΡΠΈΠΎΡΠΈΡΠ΅Ρ.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> BitmapOr
-> Bitmap Index Scan
-> Bitmap Index ScanΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠ° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ UNION [ALL] Π·Π° ΠΎΠ±Π΅Π΄ΠΈΠ½ΡΠ²Π°Π½Π΅ Π½Π° ΠΏΠΎΠ΄Π·Π°ΡΠ²ΠΊΠΈ ΠΏΠΎ Π²ΡΠ΅ΠΊΠΈ ΠΎΡ OR-Π±Π»ΠΎΠΊΠΎΠ²Π΅ΡΠ΅ Π½Π° ΡΡΠ»ΠΎΠ²ΠΈΡΡΠ°.
ΠΡΠΈΠΌΠ΅Ρ:
CREATE TABLE tbl AS
SELECT
generate_series(1, 100000) pk -- 100K "ΡΠ°ΠΊΡΠΈ"
, CASE
WHEN random() < 1::real/16 THEN NULL -- Ρ Π²Π΅ΡΠΎΡΡΠ½ΠΎΡΡ 1:16 Π·Π°ΠΏΠΈΡ "Π½ΠΈΡΠΈ"
ELSE (random() * 100)::integer -- 100 ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠΎΠ²Π΅
END fk_own;
CREATE INDEX ON tbl(fk_own, pk); -- ΠΈΠ½Π΄Π΅ΠΊΡ Ρ "Π²ΡΠΎΠ΄Π΅ ΠΊΠ°ΠΊ ΠΏΠΎΠ΄Ρ
ΠΎΠ΄ΡΡΠ°" ΡΠΎΡΡΠΈΡΠ°Π½Π΅
SELECT
*
FROM
tbl
WHERE
fk_own = 1 OR -- ΡΠ²ΠΎΠΈ
fk_own IS NULL -- ... ΠΈΠ»ΠΈ "Π½ΠΈΡΠΈ"
ORDER BY
pk
, (fk_own = 1) DESC -- ΠΏΡΡΠ²ΠΎ "ΡΠ²ΠΎΠΈ"
LIMIT 20;

ΠΠΎΠΏΡΠ°Π²ΡΠΌΠ΅:
(
SELECT
*
FROM
tbl
WHERE
fk_own = 1 -- ΠΏΡΡΠ²ΠΎ "ΡΠ²ΠΎΠΈ" 20
ORDER BY
pk
LIMIT 20
)
UNION ALL
(
SELECT
*
FROM
tbl
WHERE
fk_own IS NULL -- ΡΠ»Π΅Π΄ ΡΠΎΠ²Π° "Π½ΠΈΡΠΈ" 20
ORDER BY
pk
LIMIT 20
)
LIMIT 20; -- Π½ΠΎ ΠΎΠ±ΡΠΎ - 20, ΠΏΠΎΠ²Π΅ΡΠ΅ ΠΈ Π½Π΅ Π΅ Π½ΡΠΆΠ½ΠΎ 
ΠΡΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ ΠΌΠ΅ ΡΠ΅ ΠΎΡ ΡΠΎΠ²Π°, ΡΠ΅ Π²ΡΠΈΡΠΊΠΈΡΠ΅ 20 Π½ΡΠΆΠ½ΠΈ Π·Π°ΠΏΠΈΡΠ° Π±ΡΡ Π° Π²Π΅Π΄Π½Π°Π³Π° ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈ Π² ΠΏΡΡΠ²ΠΈΡ Π±Π»ΠΎΠΊ, ΠΏΠΎΡΠ°Π΄ΠΈ ΠΊΠΎΠ΅ΡΠΎ Π²ΡΠΎΡΠΈΡΡ, Ρ ΠΏΠΎ-Β«ΡΠΊΡΠΏΒ» Bitmap Heap Scan, Π΄ΠΎΡΠΈ Π½Π΅ Π±Π΅ΡΠ΅ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ β Π² ΡΠ΅Π·ΡΠ»ΡΠ°Ρ Π² 22 ΠΏΡΡΠΈ ΠΏΠΎ-Π±ΡΡΠ·ΠΎ, Π² 44 ΠΏΡΡΠΈ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΡ!
ΠΠΎ-ΠΏΠΎΠ΄ΡΠΎΠ±Π΅Π½ ΡΠ°Π·ΠΊΠ°Π· Π·Π° ΡΠΎΠ·ΠΈ ΠΌΠ΅ΡΠΎΠ΄ Π½Π° ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ Π½Π° ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΈ ΠΏΡΠΈΠΌΠ΅ΡΠΈ ΠΌΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΠ΅ Π² ΡΡΠ°ΡΠΈΠΈΡΠ΅ ΠΈ .
ΠΠ±ΠΎΠ±ΡΠ΅Π½ Π²Π°ΡΠΈΠ°Π½Ρ Π½Π° ΠΏΠΎΠ΄ΡΠ΅Π΄Π΅Π½ ΠΎΡΠ±ΠΎΡ ΠΏΠΎ Π½ΡΠΊΠΎΠ»ΠΊΠΎ ΠΊΠ»ΡΡΠ° (Π° Π½Π΅ ΡΠ°ΠΌΠΎ ΠΏΠΎ Π΄Π²ΠΎΠΉΠΊΠ° const/NULL) ΡΠ°Π·Π³Π»Π΅Π΄Π°Π½ Π² ΡΡΠ°ΡΠΈΡΡΠ° .
#4: ΡΠΈΡΠ°Π΅ΠΌ ΠΌΠ½ΠΎΠ³ΠΎ Π»ΠΈΡΠ½Π΅Π³ΠΎ
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
ΠΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ Π²ΡΠ·Π½ΠΈΠΊΠ²Π° ΠΏΡΠΈ ΠΆΠ΅Π»Π°Π½ΠΈΠ΅ Π΄Π° ΡΠ΅ Β«ΠΏΡΠΈΠΊΡΡΡΠΈΒ» ΠΎΡΠ΅ Π΅Π΄ΠΈΠ½ ΡΠΈΠ»ΡΡΡ ΠΊΡΠΌ Π²Π΅ΡΠ΅ ΡΡΡΠ΅ΡΡΠ²ΡΠ²Π°ΡΠ° Π·Π°ΡΠ²ΠΊΠ°.
Β«Π Π½ΡΠΌΠ°ΡΠ΅ Π»ΠΈ ΡΠ°ΠΊΠΎΠ²Π°, Π½ΠΎ Ρ ΠΏΠ΅ΡΠ»Π΅Π½ΠΈ ΠΊΠΎΠΏΡΠ΅ΡΠ°?Β» Ρ /Ρ Β«ΠΡΠΈΠ»ΡΠ½ΡΠΎΠ²Π° ΡΡΠΊΠ°Β»
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΌΠΎΠ΄ΠΈΡΠΈΡΠΈΡΠ°ΠΉΠΊΠΈ Π·Π°Π΄Π°ΡΠ°ΡΠ° ΠΏΠΎ-Π³ΠΎΡΠ΅, ΠΏΠΎΠΊΠ°ΠΆΠ΅ΡΠ΅ ΠΏΡΡΠ²ΠΈΡΠ΅ 20 Π½Π°ΠΉ-ΡΡΠ°ΡΠΈ Β«ΠΊΡΠΈΡΠΈΡΠ½ΠΈΒ» Π·Π°ΡΠ²ΠΊΠΈ Π·Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ°, Π½Π΅Π·Π°Π²ΠΈΡΠΈΠΌΠΎ ΠΎΡ ΡΠ΅Ρ Π½ΠΈΡ ΡΡΠ°ΡΡΡ.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& 5 Γ rows 80% ΠΏΡΠΎΡΠΈΡΠ°Π½Π½ΠΎΠ³ΠΎ
&& loops Γ RRbF > 100 -- ΠΈ ΠΏΡΠΈ ΡΡΠΎΠΌ Π±ΠΎΠ»ΡΡΠ΅ 100 Π·Π°ΠΏΠΈΡΠ΅ΠΉ ΡΡΠΌΠΌΠ°ΡΠ½ΠΎ
ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
Π‘ΡΠ·Π΄Π°ΠΉΡΠ΅ [ΠΏΠΎ-ΡΠΏΠ΅ΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠ°Π½] ΠΈΠ½Π΄Π΅ΠΊΡ Ρ WHERE-ΡΡΠ»ΠΎΠ²ΠΈΠ΅ ΠΈΠ»ΠΈ Π΄ΠΎΠ±Π°Π²Π΅ΡΠ΅ Π΄ΠΎΠΏΡΠ»Π½ΠΈΡΠ΅Π»Π½ΠΈ ΠΏΠΎΠ»Π΅ΡΠ° Π² ΠΈΠ½Π΄Π΅ΠΊΡΠ°.
ΠΠΊΠΎ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΡΠΎ Π·Π° ΡΠΈΠ»ΡΡΠΈΡΠ°Π½Π΅ Π΅ "ΡΡΠ°ΡΠΈΡΠ½ΠΎ" Π·Π° Π²Π°ΡΠΈΡΠ΅ Π·Π°Π΄Π°ΡΠΈ β Ρ.Π΅. Π½Π΅ ΠΏΡΠ΅Π΄Π²ΠΈΠΆΠ΄Π° ΡΠ°Π·ΡΠΈΡΠ΅Π½ΠΈΠ΅ Π½Π° ΡΠΏΠΈΡΡΠΊΠ° ΠΎΡ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈ Π² Π±ΡΠ΄Π΅ΡΠ΅ β ΠΏΠΎ-Π΄ΠΎΠ±ΡΠ΅ Π΅ Π΄Π° ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° WHERE-ΠΈΠ½Π΄Π΅ΠΊΡ. Π ΡΠ°Π·ΠΈ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡ ΡΠ΅ Π²ΠΏΠΈΡΠ²Π°Ρ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ boolean/enum-ΡΡΠ°ΡΡΡΠΈ.
ΠΠΊΠΎ Π²ΡΠ΅ ΠΏΠ°ΠΊ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΡΠΎ Π·Π° ΡΠΈΠ»ΡΡΠΈΡΠ°Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΡΠΈΠ΅ΠΌΠ° ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΡΡΠΎΠΉΠ½ΠΎΡΡΠΈ, ΡΠΎ ΠΏΠΎ-Π΄ΠΎΠ±ΡΠ΅ Π΄Π° ΡΠ°Π·ΡΠΈΡΠΈΡΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΠ° Ρ ΡΠ΅Π·ΠΈ ΠΏΠΎΠ»Π΅ΡΠ° β ΠΊΠ°ΠΊΡΠΎ Π² ΡΠΈΡΡΠ°ΡΠΈΡΡΠ° Ρ BitmapAnd ΠΏΠΎ-Π³ΠΎΡΠ΅.
ΠΡΠΈΠΌΠ΅Ρ:
Π‘ΠͺΠΠΠΠΠ Π‘Π’ΠΠ tbl AS
ΠΠΠΠΠ Π
generate_series(1, 100000) pk -- 100K "ΡΠ°ΠΊΡΠΈ"
, Π‘ΠΠ£Π§ΠΠ
ΠΠΠΠΠ’Π random() < 1::real/16 Π’ΠΠΠΠΠ NULL
ΠΠΠΠ§Π (random() * 100)::integer -- 100 ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠ°
ΠΠ ΠΠ fk_own
, (random() < 1::real/50) critical; -- 1:50, ΡΠ΅ Π·Π°ΡΠ²ΠΊΠ°ΡΠ° Π΅ "ΠΊΡΠΈΡΠΈΡΠ½Π°"
Π‘ΠͺΠΠΠΠ ΠΠΠΠΠΠ‘ ΠΠ tbl(pk);
Π‘ΠͺΠΠΠΠ ΠΠΠΠΠΠ‘ ΠΠ tbl(fk_own, pk);
ΠΠΠΠΠ Π
*
ΠΠ’
tbl
ΠΠͺΠΠ
critical
ΠΠΠ ΠΠΠ ΠΠ
pk
ΠΠΠ ΠΠΠΠ§Π 20; 
ΠΠΎΠΏΡΠ°Π²ΡΠΌΠ΅:
Π‘ΠͺΠΠΠΠ ΠΠΠΠΠΠ‘ ΠΠ tbl(pk)
ΠΠͺΠΠ critical; -- Π΄ΠΎΠ±Π°Π²ΠΈΡ
ΠΌΠ΅ "ΡΡΠ°ΡΠΈΡΠ½ΠΎ" ΡΡΠ»ΠΎΠ²ΠΈΠ΅ Π·Π° ΡΠΈΠ»ΡΡΠΈΡΠ°Π½Π΅

ΠΠ°ΠΊΡΠΎ Π²ΠΈΠΆΠ΄Π°ΠΌΠ΅, ΡΠΈΠ»ΡΡΠΈΡΠ°Π½Π΅ΡΠΎ ΠΎΡ ΠΏΠ»Π°Π½Π° Π½Π°ΠΏΡΠ»Π½ΠΎ ΠΈΠ·ΡΠ΅Π·Π½Π°, Π° Π·Π°ΡΠ²ΠΊΠ°ΡΠ° ΡΡΠ°Π½Π° Π² 5 ΠΏΡΡΠΈ ΠΏΠΎ-Π±ΡΡΠ·Π°.
#5: ΡΠ°Π·ΡΠ΅ΠΆΠ΅Π½Π½Π°Ρ ΡΠ°Π±Π»ΠΈΡΠ°
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
Π Π°Π·Π½ΠΎΠΎΠ±ΡΠ°Π·Π½ΠΈ ΠΎΠΏΠΈΡΠΈ Π·Π° ΡΡΠ·Π΄Π°Π²Π°Π½Π΅ Π½Π° ΡΠΎΠ±ΡΡΠ²Π΅Π½Π° ΠΎΠΏΠ°ΡΠΊΠ° Π·Π° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π½Π° Π·Π°Π΄Π°ΡΠΈ, ΠΊΠΎΠ³Π°ΡΠΎ Π³ΠΎΠ»ΡΠΌ Π±ΡΠΎΠΉ Π°ΠΊΡΡΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ/ΠΈΠ·ΡΡΠΈΠ²Π°Π½ΠΈΡ Π½Π° Π·Π°ΠΏΠΈΡΠΈ Π² ΡΠ°Π±Π»ΠΈΡΠ°ΡΠ° Π²ΠΎΠ΄ΡΡ Π΄ΠΎ ΡΠΈΡΡΠ°ΡΠΈΡ Ρ ΠΌΠ½ΠΎΠ³ΠΎ "ΠΌΡΡΡΠ²ΠΈ" Π·Π°ΠΏΠΈΡΠΈ.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& loops Γ (rows + RRbF) 64
ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
Π Π΅Π΄ΠΎΠ²Π½ΠΎ ΡΡΡΠ½ΠΎ ΠΏΡΠΎΠ²Π΅ΠΆΠ΄Π°Π½Π΅ Π½Π° VACUUM [FULL] ΠΈΠ»ΠΈ Π΄ΠΎΡΡΠΈΠ³Π°Π½Π΅ Π½Π° Π°Π΄Π΅ΠΊΠ²Π°ΡΠ½ΠΎ ΡΠ΅ΡΡΠΎ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ ΡΡΠ΅Π· ΠΏΡΠ΅ΡΠΈΠ·Π½ΠΎ Π½Π°ΡΡΡΠΎΠΉΠ²Π°Π½Π΅ Π½Π° Π½Π΅Π³ΠΎΠ²ΠΈΡΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΈ, Π² ΡΠΎΠ²Π° ΡΠΈΡΠ»ΠΎ .
Π ΠΏΠΎΠ²Π΅ΡΠ΅ΡΠΎ ΡΠ»ΡΡΠ°ΠΈ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌΠΈ ΡΠ΅ ΠΎΠΊΠ°Π·Π²Π°Ρ ΠΏΡΠ΅Π΄ΠΈΠ·Π²ΠΈΠΊΠ°Π½ΠΈ ΠΎΡ Π»ΠΎΡΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½ΠΈΡΠ°Π½Π΅ Π½Π° Π·Π°ΡΠ²ΠΊΠΈ ΠΏΡΠΈ ΠΏΠΎΠ²ΠΈΠΊΠ²Π°Π½ΠΈΡ Ρ Π±ΠΈΠ·Π½Π΅Ρ Π»ΠΎΠ³ΠΈΠΊΠ° ΠΊΠ°ΡΠΎ ΡΠ΅Π·ΠΈ, ΠΊΠΎΠΈΡΠΎ Π±ΡΡ Π° ΠΎΠ±ΡΡΠ΄Π΅Π½ΠΈ Π² .
ΠΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΡΠ΅ ΡΠ°Π·Π±Π΅ΡΠ΅, ΡΠ΅ Π΄ΠΎΡΠΈ VACUUM FULL Π½Π΅ ΠΌΠΎΠΆΠ΅ Π΄Π° ΠΏΠΎΠΌΠΎΠ³Π½Π΅ Π²ΠΈΠ½Π°Π³ΠΈ. ΠΠ° ΡΠ°ΠΊΠΈΠ²Π° ΡΠ»ΡΡΠ°ΠΈ Π΅ Π΄ΠΎΠ±ΡΠ΅ Π΄Π° ΡΠ΅ Π·Π°ΠΏΠΎΠ·Π½Π°Π΅ΡΠ΅ Ρ Π°Π»Π³ΠΎΡΠΈΡΡΠΌΠ° ΠΎΡ ΡΡΠ°ΡΠΈΡΡΠ° .
#6: ΡΡΠ΅Π½ΠΈΠ΅ Ρ Β«ΡΠ΅ΡΠ΅Π΄ΠΈΠ½ΡΒ» ΠΈΠ½Π΄Π΅ΠΊΡΠ°
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
ΠΠ·Π³Π»Π΅ΠΆΠ΄Π°, ΡΠ΅ ΡΠΌΠ΅ ΠΏΡΠΎΡΠ΅Π»ΠΈ ΠΌΠ°Π»ΠΊΠΎ, Π²ΡΠΈΡΠΊΠΎ Π΅ ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΠ° ΠΈ Π½ΠΈΠΊΠΎΠ³ΠΎ Π½Π΅Π½ΡΠΆΠ½ΠΎ Π½Π΅ ΡΠΌΠ΅ ΡΠΈΠ»ΡΡΠΈΡΠ°Π»ΠΈ β Π° Π²ΡΠ΅ ΠΏΠ°ΠΊ ΠΏΡΠΎΡΠ΅ΡΠ΅Π½ΠΈΡΠ΅ ΡΡΡΠ°Π½ΠΈΡΠΈ ΡΠ° Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΠΏΠΎΠ²Π΅ΡΠ΅, ΠΎΡΠΊΠΎΠ»ΠΊΠΎΡΠΎ Π±ΠΈΡ ΠΌΠ΅ ΠΆΠ΅Π»Π°Π»ΠΈ.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> Index [Only] Scan [Backward]
&& loops Γ (rows + RRbF) 64
ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠ½ΠΈΠΌΠ°ΡΠ΅Π»Π½ΠΎ ΡΠ°Π·Π³Π»Π΅Π΄Π°ΠΉΡΠ΅ ΡΡΡΡΠΊΡΡΡΠ°ΡΠ° Π½Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΈΡ ΠΈΠ½Π΄Π΅ΠΊΡ ΠΈ ΠΊΠ»ΡΡΠΎΠ²ΠΈΡΠ΅ ΠΏΠΎΠ»Π΅ΡΠ°, Π·Π°Π΄Π°Π΄Π΅Π½ΠΈ Π² Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅ΡΠΎ - Π²Π΅ΡΠΎΡΡΠ½ΠΎ, ΡΠ°ΡΡ ΠΎΡ ΠΈΠ½Π΄Π΅ΠΊΡΠ° Π½Π΅ Π΅ Π·Π°Π΄Π°Π΄Π΅Π½Π°. ΠΠ΅ΡΠΎΡΡΠ½ΠΎ ΡΠ΅ ΡΡΡΠ±Π²Π° Π΄Π° ΡΡΠ·Π΄Π°Π΄Π΅ΡΠ΅ ΠΏΠΎΠ΄ΠΎΠ±Π΅Π½ ΠΈΠ½Π΄Π΅ΠΊΡ, Π½ΠΎ Π±Π΅Π· ΠΏΡΠ΅ΡΠΈΠΊΡΠ½ΠΈ ΠΏΠΎΠ»Π΅ΡΠ° ΠΈΠ»ΠΈ .
ΠΡΠΈΠΌΠ΅Ρ:
CREATE TABLE tbl AS
SELECT
generate_series(1, 100000) pk -- 100K "ΡΠ°ΠΊΡΠΈ"
, (random() * 100)::integer fk_org -- 100 ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠ°
, (random() * 1000)::integer fk_cli; -- 1K ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ Π²ΡΠ½ΡΠ½ΠΈ ΠΊΠ»ΡΡΠ°
CREATE INDEX ON tbl(fk_org, fk_cli); -- Π²ΡΠΈΡΠΊΠΎ ΠΏΠΎΡΡΠΈ ΠΊΠ°ΠΊΡΠΎ Π² #2
-- ΡΠ°ΠΌΠΎ ΡΠ΅ ΠΎΡΠ΄Π΅Π»Π½ΠΈΡΡ ΠΈΠ½Π΄Π΅ΠΊΡ ΠΏΠΎ fk_cli Π²Π΅ΡΠ΅ Π³ΠΎ ΡΠΌΠ΅ΡΠ½Π°Ρ
ΠΌΠ΅ Π·Π° ΠΈΠ·Π»ΠΈΡΠ΅Π½ ΠΈ Π³ΠΎ ΠΏΡΠ΅ΠΌΠ°Ρ
Π½Π°Ρ
ΠΌΠ΅
SELECT
*
FROM
tbl
WHERE
fk_cli = 999 -- Π° fk_org Π½Π΅ Π΅ Π·Π°Π΄Π°Π΄Π΅Π½, Π²ΡΠΏΡΠ΅ΠΊΠΈ ΡΠ΅ ΡΡΠΎΠΈ ΠΏΠΎ-ΡΠ°Π½ΠΎ Π² ΠΈΠ½Π΄Π΅ΠΊΡΠ°
LIMIT 20; 
ΠΠ·Π³Π»Π΅ΠΆΠ΄Π° Π²ΡΠΈΡΠΊΠΎ Π΅ Π½Π°ΡΠ΅Π΄, Π΄ΠΎΡΠΈ ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΠ°, Π½ΠΎ ΠΏΠΎ Π½ΡΠΊΠ°ΠΊΡΠ² Π½Π°ΡΠΈΠ½ Π΅ ΠΏΠΎΠ΄ΠΎΠ·ΡΠΈΡΠ΅Π»Π½ΠΎ - Π½Π° Π²ΡΡΠΊΠ° ΠΎΡ 20-ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΠ΅Π½ΠΈ Π·Π°ΠΏΠΈΡΠΈ ΡΠ΅ Π½Π°Π»ΠΎΠΆΠΈ Π΄Π° ΡΠ΅ ΠΈΠ·Π²Π»Π΅ΠΊΠ°Ρ ΠΏΠΎ 4 ΡΡΡΠ°Π½ΠΈΡΠΈ Π΄Π°Π½Π½ΠΈ, 32KB Π½Π° Π·Π°ΠΏΠΈΡ - Π½Π΅ Π΅ Π»ΠΈ ΡΠ²ΡΡΠ΄Π΅ ΠΌΠ½ΠΎΠ³ΠΎ? Π ΠΈΠΌΠ΅ΡΠΎ Π½Π° ΠΈΠ½Π΄Π΅ΠΊΡΠ° tbl_fk_org_fk_cli_idx ΠΏΡΠ΅Π΄ΠΈΠ·Π²ΠΈΠΊΠ²Π° ΡΠ°Π·ΠΌΠΈΡΠ»ΠΈ.
ΠΠΎΠΏΡΠ°Π²ΡΠΌΠ΅:
CREATE INDEX ON tbl(fk_cli); 
ΠΠ΅ΠΎΡΠ°ΠΊΠ²Π°Π½ΠΎ - 10 ΠΏΡΡΠΈ ΠΏΠΎ-Π±ΡΡΠ·ΠΎ, ΠΈ 4 ΠΏΡΡΠΈ ΠΏΠΎ-ΠΌΠ°Π»ΠΊΠΎ ΡΠ΅ΡΠ΅Π½Π΅!
ΠΡΡΠ³ΠΈ ΠΏΡΠΈΠΌΠ΅ΡΠΈ Π·Π° ΡΠΈΡΡΠ°ΡΠΈΠΈ Ρ Π½Π΅Π΅ΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½Π΅ Π½Π° ΠΈΠ½Π΄Π΅ΠΊΡΠΈ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π΄Π° Π²ΠΈΠ΄ΠΈΡΠ΅ Π² ΡΡΠ°ΡΠΈΡΡΠ° .
#7: CTE Γ CTE
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
Π Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅ΡΠΎ ΡΡΠ±ΡΠ°Ρ
ΠΌΠ΅ "Π΄Π΅Π±Π΅Π»ΠΈ" CTE ΠΎΡ ΡΠ°Π·Π»ΠΈΡΠ½ΠΈ ΡΠ°Π±Π»ΠΈΡΠΈ, Π° ΡΠ»Π΅Π΄ ΡΠΎΠ²Π° ΡΠ΅ΡΠΈΡ
ΠΌΠ΅ Π΄Π° Π½Π°ΠΏΡΠ°Π²ΠΈΠΌ ΠΌΠ΅ΠΆΠ΄Ρ ΡΡΡ
JOIN.
Π‘Π»ΡΡΠ°ΡΡ Π΅ Π°ΠΊΡΡΠ°Π»Π΅Π½ Π·Π° Π²Π΅ΡΡΠΈΠΈ ΠΏΠΎΠ΄ v12 ΠΈΠ»ΠΈ Π·Π°ΠΏΠΈΡΠ²Π°Π½ΠΈΡ Ρ WITH MATERIALIZED.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> CTE Scan
&& ΡΠΈΠΊΠ»ΠΈ > 10
&& ΡΠΈΠΊΠ»ΠΈ Γ (ΡΠ΅Π΄ΠΎΠ²Π΅ + RRbF) > 10000
-- ΡΠ²ΡΡΠ΄Π΅ Π³ΠΎΠ»ΡΠΌΠΎ Π΄Π΅ΠΊΠ°ΡΡΠΎΠ²ΠΎ ΠΏΡΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½ΠΈΠ΅ CTE
ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠ½ΠΈΠΌΠ°ΡΠ΅Π»Π½ΠΎ Π°Π½Π°Π»ΠΈΠ·ΠΈΡΠ°ΠΉΡΠ΅ Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅ΡΠΎ - Π° ? ΠΡΠ»ΠΈ Π²ΡΠ΅-ΡΠ°ΠΊΠΈ Π΄Π°, ΡΠΎ Π΄Π° ΠΏΡΠΈΠ»ΠΎΠΆΠΈΡΠ΅ "ΠΎΡΠ»ΠΎΠ²ΠΎΡΡΠ½Π΅" Π² hstore/json ΠΏΠΎ ΠΌΠΎΠ΄Π΅Π»Π°, ΠΎΠΏΠΈΡΠ°Π½ Π² .
#8: swap Π½Π° Π΄ΠΈΡΠΊ (temp written)
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
ΠΠ΄Π½ΠΎΠΊΡΠ°ΡΠ½Π°ΡΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° (ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠ° ΠΈΠ»ΠΈ ΡΠ½ΠΈΠΊΠ°Π»ΠΈΠ·Π°ΡΠΈΡ) Π½Π° Π³ΠΎΠ»ΡΠΌΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π·Π°ΠΏΠΈΡΠΈ Π½Π΅ ΡΠ΅ ΠΏΠΎΠ±ΠΈΡΠ° Π² ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π°ΡΠ° Π·Π° ΡΠΎΠ²Π° ΠΏΠ°ΠΌΠ΅Ρ.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> *
&& temp written > 0ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠΊΠΎ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Π½ΠΎΡΠΎ ΠΎΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡΡΠ° ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΏΠ°ΠΌΠ΅Ρ Π½Π΅ Π½Π°Π΄Π²ΠΈΡΠ°Π²Π° Π·Π½Π°ΡΠΈΡΠ΅Π»Π½ΠΎ ΡΡΡΠ°Π½ΠΎΠ²Π΅Π½Π°ΡΠ° ΡΡΠΎΠΉΠ½ΠΎΡΡ Π½Π° ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡΠ° , ΡΡΡΡΠ²Π° ΡΠΈ Π΄Π° Π³ΠΎ ΠΊΠΎΡΠΈΠ³ΠΈΡΠ°ΡΠ΅. ΠΠΎΠΆΠ΅ Π΄Π° ΡΠ΅ Π½Π°ΠΏΡΠ°Π²ΠΈ Π²Π΅Π΄Π½Π°Π³Π° Π² ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡΡΠ° Π·Π° Π²ΡΠΈΡΠΊΠΈ, ΠΈΠ»ΠΈ ΡΡΠ΅Π· SET [LOCAL] Π·Π° ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎ Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅/ΡΡΠ°Π½Π·Π°ΠΊΡΠΈΡ.
ΠΡΠΈΠΌΠ΅Ρ:
SHOW work_mem;
-- "16MB"
SELECT
random()
FROM
generate_series(1, 1000000)
ORDER BY
1; 
ΠΠΎΠΏΡΠ°Π²ΡΠΌΠ΅:
SET work_mem = '128MB'; -- ΠΏΡΠ΅Π΄ΠΈ ΠΈΠ·ΠΏΡΠ»Π½Π΅Π½ΠΈΠ΅ΡΠΎ Π½Π° Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅ΡΠΎ 
ΠΠΎ ΡΠ°Π·Π±ΠΈΡΠ°Π΅ΠΌΠΈ ΠΏΡΠΈΡΠΈΠ½ΠΈ, Π°ΠΊΠΎ ΡΠ΅ ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π° ΡΠ°ΠΌΠΎ ΠΏΠ°ΠΌΠ΅Ρ, Π° Π½Π΅ Π΄ΠΈΡΠΊ, Π·Π°ΠΏΠΈΡΠ²Π°Π½Π΅ΡΠΎ ΡΡΡΠΎ ΡΠ΅ ΡΠ΅ ΠΈΠ·ΠΏΡΠ»Π½ΡΠ²Π° ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠΎ-Π±ΡΡΠ·ΠΎ. Π ΡΡΡΠΎΡΠΎ Π²ΡΠ΅ΠΌΠ΅ ΡΠ°ΡΡ ΠΎΡ Π½Π°ΡΠΎΠ²Π°ΡΠ²Π°Π½Π΅ΡΠΎ ΠΎΡ HDD ΡΠ΅ ΠΎΡΡΡΡΠ°Π½ΡΠ²Π°.
ΠΠΎ ΡΡΡΠ±Π²Π° Π΄Π° ΡΠ°Π·Π±Π΅ΡΠ΅ΡΠ΅, ΡΠ΅ Π½Π΅ ΠΌΠΎΠΆΠ΅ Π²ΠΈΠ½Π°Π³ΠΈ Π΄Π° ΡΠ΅ ΠΎΡΠ΄Π΅Π»Ρ ΠΌΠ½ΠΎΠ³ΠΎ-ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΠ°ΠΌΠ΅Ρ - ΠΏΡΠΎΡΡΠΎ Π½ΡΠΌΠ° Π΄Π° ΡΡΠΈΠ³Π½Π΅ Π·Π° Π²ΡΠΈΡΠΊΠΈ.
#9: Π½Π΅Π°ΠΊΡΡΠ°Π»ΡΠ½Π°Ρ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ°
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
Π Π±Π°Π·Π°ΡΠ° Π΄Π°Π½Π½ΠΈ Π±ΡΡ
Π° Π²ΠΊΠ°ΡΠ°Π½ΠΈ ΠΌΠ½ΠΎΠ³ΠΎ Π·Π°ΠΏΠΈΡΠΈ, Π½ΠΎ Π½Π΅ ΡΡΠΏΡΡ
Π° Π΄Π° ΠΏΡΠ΅ΠΌΠΈΠ½Π°Ρ ANALYZE.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& ratio >> 10ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠ° ΠΏΡΠΎΠ²Π΅Π΄Π΅ΠΌ Π²ΡΠ΅ ΠΏΠ°ΠΊ ANALYZE.
ΠΠΎ-ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎ, ΡΠΈΡΡΠ°ΡΠΈΡ Π΅ ΠΎΠΏΠΈΡΠ°Π½Π° Π² .
#10: Β«ΡΡΠΎ-ΡΠΎ ΠΏΠΎΡΠ»ΠΎ Π½Π΅ ΡΠ°ΠΊΒ»
ΠΠΎΠ³Π° Π²ΡΠ·Π½ΠΈΠΊΠ²Π°
Π‘Π»ΡΡΠΈ ΡΠ΅ ΡΠ°ΠΊΠ°Π½Π΅ Π½Π° Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠ°, Π½Π°Π»ΠΎΠΆΠ΅Π½Π° ΠΎΡ ΠΊΠΎΠ½ΠΊΡΡΠ΅Π½ΡΠ½Π° Π·Π°ΡΠ²ΠΊΠ°, ΠΈΠ»ΠΈ Π»ΠΈΠΏΡΠ²Π°Ρ Π° Ρ Π°ΡΠ΄ΡΠ΅ΡΠ½ΠΈ ΡΠ΅ΡΡΡΡΠΈ CPU/Ρ ΠΈΠΏΠ΅ΡΠ²ΠΈΠ·ΠΎΡ.
ΠΠ°ΠΊ Π΄Π° ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΡΠΈΡΠ°ΠΌΠ΅
-> *
&& (shared hit / 8K) + (shared read / 1K) < time / 1000
-- RAM hit = 64MB/s, HDD read = 8MB/s
&& time > 100ms -- ΡΠ΅ΡΠ΅Π½Π΅ΡΠΎ Π±Π΅ΡΠ΅ ΠΌΠ°Π»ΠΊΠΎ, Π½ΠΎ ΠΎΡΠ½Π΅ ΡΠ²ΡΡΠ΄Π΅ ΠΌΠ½ΠΎΠ³ΠΎ Π²ΡΠ΅ΠΌΠ΅
ΠΡΠ΅ΠΏΠΎΡΡΠΊΠΈ
ΠΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΉΡΠ΅ Π²ΡΠ½ΡΠ½Π° ΡΠΈΡΡΠ΅ΠΌΠ° Π·Π° ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ Π½Π° ΡΡΡΠ²ΡΡΠΈ Π·Π° Π½Π°Π»ΠΈΡΠΈΠ΅ Π½Π° Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠΈ ΠΈΠ»ΠΈ Π½Π΅Π½ΠΎΡΠΌΠ°Π»Π½ΠΎ ΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΠ΅ Π½Π° ΡΠ΅ΡΡΡΡΠΈ. ΠΠ° Π½Π°ΡΠΈΡ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ ΠΊΡΠΌ ΠΎΡΠ³Π°Π½ΠΈΠ·ΠΈΡΠ°Π½Π΅ Π½Π° ΡΠΎΠ·ΠΈ ΠΏΡΠΎΡΠ΅Ρ Π·Π° ΡΡΠΎΡΠΈΡΠΈ ΡΡΡΠ²ΡΡΠΈ Π²Π΅ΡΠ΅ Π³ΠΎΠ²ΠΎΡΠΈΡ ΠΌΠ΅ ΠΈ .


ΠΠ·ΡΠΎΡΠ½ΠΈΠΊ: habr.com
