ΠΠ΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΌΠ΅ΡΡΡΠ΅Π² Π½Π°Π·Π°Π΄
ΠΠ° ΠΏΡΠΎΡΠ΅Π΄ΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ Π²Ρ ΡΠΆΠ΅ Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π»ΠΈΡΡ ΠΈΠΌ Π±ΠΎΠ»Π΅Π΅ 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
Π½Π΅ Π±ΡΠ»ΠΎ ΠΈ Π½Π΅Ρ (ΠΏΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ ΠΏΡΠΎ ΡΡΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠΎΡΠΈΡΠ°ΡΡ
#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 ΡΠ°Π·Π° ΠΌΠ΅Π½ΡΡΠ΅ ΡΡΠ΅Π½ΠΈΠΉ!
ΠΠΎΠ»Π΅Π΅ Π΄Π΅ΡΠ°Π»ΡΠ½ΡΠΉ ΡΠ°ΡΡΠΊΠ°Π· ΠΎ Π΄Π°Π½Π½ΠΎΠΌ ΡΠΏΠΎΡΠΎΠ±Π΅ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ Π½Π° ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΡ ΠΏΡΠΈΠΌΠ΅ΡΠ°Ρ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠΎΡΠΈΡΠ°ΡΡ Π² ΡΡΠ°ΡΡΡΡ
PostgreSQL Antipatterns: Π²ΡΠ΅Π΄Π½ΡΠ΅ JOIN ΠΈ OR ΠΈPostgreSQL Antipatterns: ΡΠΊΠ°Π· ΠΎΠ± ΠΈΡΠ΅ΡΠ°ΡΠΈΠ²Π½ΠΎΠΉ Π΄ΠΎΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΏΠΎΠΈΡΠΊΠ° ΠΏΠΎ Π½Π°Π·Π²Π°Π½ΠΈΡ, ΠΈΠ»ΠΈ Β«ΠΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΡ ΡΡΠ΄Π° ΠΈ ΠΎΠ±ΡΠ°ΡΠ½ΠΎΒ» .ΠΠ±ΠΎΠ±ΡΠ΅Π½Π½ΡΠΉ Π²Π°ΡΠΈΠ°Π½Ρ ΡΠΏΠΎΡΡΠ΄ΠΎΡΠ΅Π½Π½ΠΎΠ³ΠΎ ΠΎΡΠ±ΠΎΡΠ° ΠΏΠΎ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΈΠΌ ΠΊΠ»ΡΡΠ°ΠΌ (Π° Π½Π΅ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎ ΠΏΠ°ΡΠ΅ const/NULL) ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π½ Π² ΡΡΠ°ΡΡΠ΅
SQL HowTo: ΠΏΠΈΡΠ΅ΠΌ while-ΡΠΈΠΊΠ» ΠΏΡΡΠΌΠΎ Π² Π·Π°ΠΏΡΠΎΡΠ΅, ΠΈΠ»ΠΈ Β«ΠΠ»Π΅ΠΌΠ΅Π½ΡΠ°ΡΠ½Π°Ρ ΡΡΠ΅Ρ Ρ ΠΎΠ΄ΠΎΠ²ΠΊΠ°Β» .
#4: ΡΠΈΡΠ°Π΅ΠΌ ΠΌΠ½ΠΎΠ³ΠΎ Π»ΠΈΡΠ½Π΅Π³ΠΎ
ΠΠΎΠ³Π΄Π° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ
ΠΠ°ΠΊ ΠΏΡΠ°Π²ΠΈΠ»ΠΎ, Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ ΠΏΡΠΈ ΠΆΠ΅Π»Π°Π½ΠΈΠΈ Β«ΠΏΡΠΈΠΊΡΡΡΠΈΡΡ Π΅ΡΠ΅ ΠΎΠ΄ΠΈΠ½ ΡΠΈΠ»ΡΡΡΒ» ΠΊ ΡΠΆΠ΅ ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠ΅ΠΌΡ Π·Π°ΠΏΡΠΎΡΡ.
Β«Π Ρ Π²Π°Ρ Π½Π΅Ρ ΡΠ°ΠΊΠΎΠ³ΠΎ ΠΆΠ΅, Π½ΠΎ Ρ ΠΏΠ΅ΡΠ»Π°ΠΌΡΡΡΠΎΠ²ΡΠΌΠΈ ΠΏΡΠ³ΠΎΠ²ΠΈΡΠ°ΠΌΠΈ?Β» Ρ /Ρ Β«ΠΡΠΈΠ»Π»ΠΈΠ°Π½ΡΠΎΠ²Π°Ρ ΡΡΠΊΠ°Β»
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΠΌΠΎΠ΄ΠΈΡΠΈΡΠΈΡΡΡ Π·Π°Π΄Π°ΡΡ Π²ΡΡΠ΅, ΠΏΠΎΠΊΠ°Π·Π°ΡΡ ΠΏΠ΅ΡΠ²ΡΠ΅ 20 ΡΠ°ΠΌΡΡ ΡΡΠ°ΡΡΡ Β«ΠΊΡΠΈΡΠΈΡΠ½ΡΡ Β» Π·Π°ΡΠ²ΠΎΠΊ Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ, Π½Π΅Π·Π°Π²ΠΈΡΠΈΠΌΠΎ ΠΎΡ ΠΈΡ Π½Π°Π·Π½Π°ΡΠ΅Π½Π½ΠΎΡΡΠΈ.
ΠΠ°ΠΊ ΠΎΠΏΠΎΠ·Π½Π°ΡΡ
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& 5 Γ rows < RRbF -- ΠΎΡΡΠΈΠ»ΡΡΡΠΎΠ²Π°Π½ΠΎ >80% ΠΏΡΠΎΡΠΈΡΠ°Π½Π½ΠΎΠ³ΠΎ
&& loops Γ RRbF > 100 -- ΠΈ ΠΏΡΠΈ ΡΡΠΎΠΌ Π±ΠΎΠ»ΡΡΠ΅ 100 Π·Π°ΠΏΠΈΡΠ΅ΠΉ ΡΡΠΌΠΌΠ°ΡΠ½ΠΎ
Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΠΈ
Π‘ΠΎΠ·Π΄Π°ΡΡ [Π±ΠΎΠ»Π΅Π΅] ΡΠΏΠ΅ΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΠΈΠ½Π΄Π΅ΠΊΡ Ρ WHERE-ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΠΌ ΠΈΠ»ΠΈ Π²ΠΊΠ»ΡΡΠΈΡΡ Π² ΠΈΠ½Π΄Π΅ΠΊΡ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ ΠΏΠΎΠ»Ρ.
ΠΡΠ»ΠΈ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠΈ ΡΠ²Π»ΡΠ΅ΡΡΡ Β«ΡΡΠ°ΡΠΈΡΠ½ΡΠΌΒ» Π΄Π»Ρ Π²Π°ΡΠΈΡ Π·Π°Π΄Π°Ρ β ΡΠΎ Π΅ΡΡΡ Π½Π΅ ΠΏΡΠ΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π΅Ρ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ ΠΏΠ΅ΡΠ΅ΡΠ½Ρ Π·Π½Π°ΡΠ΅Π½ΠΈΠΉ Π² Π±ΡΠ΄ΡΡΠ΅ΠΌ β Π»ΡΡΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ WHERE-ΠΈΠ½Π΄Π΅ΠΊΡ. Π ΡΡΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΡ Ρ ΠΎΡΠΎΡΠΎ ΡΠΊΠ»Π°Π΄ΡΠ²Π°ΡΡΡΡ ΡΠ°Π·Π½ΡΠ΅ boolean/enum-ΡΡΠ°ΡΡΡΡ.
ΠΡΠ»ΠΈ ΠΆΠ΅ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠΈ ΠΌΠΎΠΆΠ΅Ρ ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ ΡΠ°Π·Π½ΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ, ΡΠΎ Π»ΡΡΡΠ΅ ΡΠ°ΡΡΠΈΡΠΈΡΡ ΠΈΠ½Π΄Π΅ΠΊΡ ΡΡΠΈΠΌΠΈ ΠΏΠΎΠ»ΡΠΌΠΈ β ΠΊΠ°ΠΊ Π² ΡΠΈΡΡΠ°ΡΠΈΠΈ Ρ BitmapAnd Π²ΡΡΠ΅.
ΠΡΠΈΠΌΠ΅Ρ:
CREATE TABLE tbl AS
SELECT
generate_series(1, 100000) pk -- 100K "ΡΠ°ΠΊΡΠΎΠ²"
, CASE
WHEN random() < 1::real/16 THEN NULL
ELSE (random() * 100)::integer -- 100 ΡΠ°Π·Π½ΡΡ
Π²Π½Π΅ΡΠ½ΠΈΡ
ΠΊΠ»ΡΡΠ΅ΠΉ
END fk_own
, (random() < 1::real/50) critical; -- 1:50, ΡΡΠΎ Π·Π°ΡΠ²ΠΊΠ° "ΠΊΡΠΈΡΠΈΡΠ½Π°Ρ"
CREATE INDEX ON tbl(pk);
CREATE INDEX ON tbl(fk_own, pk);
SELECT
*
FROM
tbl
WHERE
critical
ORDER BY
pk
LIMIT 20;
ΠΡΠΏΡΠ°Π²Π»ΡΠ΅ΠΌ:
CREATE INDEX ON tbl(pk)
WHERE critical; -- Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ "ΡΡΠ°ΡΠΈΡΠ½ΠΎΠ΅" ΡΡΠ»ΠΎΠ²ΠΈΠ΅ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠΈ
ΠΠ°ΠΊ Π²ΠΈΠ΄ΠΈΠΌ, ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ ΠΈΠ· ΠΏΠ»Π°Π½Π° ΠΏΠΎΠ»Π½ΠΎΡΡΡΡ ΡΡΠ»Π°, Π° Π·Π°ΠΏΡΠΎΡ ΡΡΠ°Π» Π² 5 ΡΠ°Π· Π±ΡΡΡΡΠ΅Π΅.
#5: ΡΠ°Π·ΡΠ΅ΠΆΠ΅Π½Π½Π°Ρ ΡΠ°Π±Π»ΠΈΡΠ°
ΠΠΎΠ³Π΄Π° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ
Π Π°Π·Π½ΠΎΠΎΠ±ΡΠ°Π·Π½ΡΠ΅ ΠΏΠΎΠΏΡΡΠΊΠΈ ΡΠ΄Π΅Π»Π°ΡΡ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π·Π°Π΄Π°Ρ, ΠΊΠΎΠ³Π΄Π° Π±ΠΎΠ»ΡΡΠΎΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ/ΡΠ΄Π°Π»Π΅Π½ΠΈΠΉ Π·Π°ΠΏΠΈΡΠ΅ΠΉ Π½Π° ΡΠ°Π±Π»ΠΈΡΠ΅ ΠΏΡΠΈΠ²ΠΎΠ΄ΡΡ ΠΊ ΡΠΈΡΡΠ°ΡΠΈΠΈ Π±ΠΎΠ»ΡΡΠΎΠ³ΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° Β«ΠΌΠ΅ΡΡΠ²ΡΡ Β» Π·Π°ΠΏΠΈΡΠ΅ΠΉ.
ΠΠ°ΠΊ ΠΎΠΏΠΎΠ·Π½Π°ΡΡ
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& loops Γ (rows + RRbF) < (shared hit + shared read) Γ 8
-- ΠΏΡΠΎΡΠΈΡΠ°Π½ΠΎ Π±ΠΎΠ»ΡΡΠ΅ 1KB Π½Π° ΠΊΠ°ΠΆΠ΄ΡΡ Π·Π°ΠΏΠΈΡΡ
&& shared hit + shared read > 64
Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΠΈ
Π Π΅Π³ΡΠ»ΡΡΠ½ΠΎ Π²ΡΡΡΠ½ΡΡ ΠΏΡΠΎΠ²ΠΎΠ΄ΠΈΡΡ VACUUM [FULL] ΠΈΠ»ΠΈ Π΄ΠΎΠ±ΠΈΡΡΡΡ Π°Π΄Π΅ΠΊΠ²Π°ΡΠ½ΠΎ ΡΠ°ΡΡΠΎΠΉ ΠΎΡΡΠ°Π±ΠΎΡΠΊΠΈ
Π Π±ΠΎΠ»ΡΡΠΈΠ½ΡΡΠ²Π΅ ΡΠ»ΡΡΠ°Π΅Π² ΠΏΠΎΠ΄ΠΎΠ±Π½ΡΠ΅ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ ΠΎΠΊΠ°Π·ΡΠ²Π°ΡΡΡΡ Π²ΡΠ·Π²Π°Π½Ρ ΠΏΠ»ΠΎΡ ΠΎΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½ΠΎΠ²ΠΊΠΎΠΉ Π·Π°ΠΏΡΠΎΡΠΎΠ² ΠΏΡΠΈ Π²ΡΠ·ΠΎΠ²Π°Ρ Ρ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΠΈ Π²ΡΠΎΠ΄Π΅ ΡΠ΅Ρ , ΠΊΠΎΡΠΎΡΡΠ΅ Π±ΡΠ»ΠΈ ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π½Ρ Π²
PostgreSQL Antipatterns: ΡΡΠ°ΠΆΠ°Π΅ΠΌΡΡ Ρ ΠΎΡΠ΄Π°ΠΌΠΈ Β«ΠΌΠ΅ΡΡΠ²Π΅ΡΠΎΠ²Β» .ΠΠΎ Π½Π°Π΄ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°ΡΡ, ΡΡΠΎ Π΄Π°ΠΆΠ΅ VACUUM FULL ΠΌΠΎΠΆΠ΅Ρ ΠΏΠΎΠΌΠΎΡΡ Π½Π΅ Π²ΡΠ΅Π³Π΄Π°. ΠΠ»Ρ ΡΠ°ΠΊΠΈΡ ΡΠ»ΡΡΠ°Π΅Π² ΡΡΠΎΠΈΡ ΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡΡΡΡ Ρ Π°Π»Π³ΠΎΡΠΈΡΠΌΠΎΠΌ ΠΈΠ· ΡΡΠ°ΡΡΠΈ
DBA: ΠΊΠΎΠ³Π΄Π° ΠΏΠ°ΡΡΠ΅Ρ VACUUM β ΡΠΈΡΡΠΈΠΌ ΡΠ°Π±Π»ΠΈΡΡ Π²ΡΡΡΠ½ΡΡ .
#6: ΡΡΠ΅Π½ΠΈΠ΅ Ρ Β«ΡΠ΅ΡΠ΅Π΄ΠΈΠ½ΡΒ» ΠΈΠ½Π΄Π΅ΠΊΡΠ°
ΠΠΎΠ³Π΄Π° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ
ΠΡΠΎΠ΄Π΅ ΠΈ ΠΏΡΠΎΡΠΈΡΠ°Π»ΠΈ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ, ΠΈ Π²ΡΠ΅ ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΡ, ΠΈ Π½ΠΈΠΊΠΎΠ³ΠΎ Π»ΠΈΡΠ½Π΅Π³ΠΎ Π½Π΅ ΡΠΈΠ»ΡΡΡΠΎΠ²Π°Π»ΠΈ β Π° Π²ΡΠ΅ ΡΠ°Π²Π½ΠΎ ΠΏΡΠΎΡΠΈΡΠ°Π½ΠΎ ΡΡΡΠ΅ΡΡΠ²Π΅Π½Π½ΠΎ Π±ΠΎΠ»ΡΡΠ΅ ΡΡΡΠ°Π½ΠΈΡ, ΡΠ΅ΠΌ Ρ ΠΎΡΠ΅Π»ΠΎΡΡ Π±Ρ.
ΠΠ°ΠΊ ΠΎΠΏΠΎΠ·Π½Π°ΡΡ
-> Index [Only] Scan [Backward]
&& loops Γ (rows + RRbF) < (shared hit + shared read) Γ 8
-- ΠΏΡΠΎΡΠΈΡΠ°Π½ΠΎ Π±ΠΎΠ»ΡΡΠ΅ 1KB Π½Π° ΠΊΠ°ΠΆΠ΄ΡΡ Π·Π°ΠΏΠΈΡΡ
&& shared hit + shared read > 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 ΡΠ°Π·Π° ΠΌΠ΅Π½ΡΡΠ΅ ΡΠΈΡΠ°ΡΡ!
ΠΡΡΠ³ΠΈΠ΅ ΠΏΡΠΈΠΌΠ΅ΡΡ ΡΠΈΡΡΠ°ΡΠΈΠΉ Π½Π΅ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ ΠΈΠ½Π΄Π΅ΠΊΡΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ ΡΠ²ΠΈΠ΄Π΅ΡΡ Π² ΡΡΠ°ΡΡΠ΅
DBA: Π½Π°Ρ ΠΎΠ΄ΠΈΠΌ Π±Π΅ΡΠΏΠΎΠ»Π΅Π·Π½ΡΠ΅ ΠΈΠ½Π΄Π΅ΠΊΡΡ .
#7: CTE Γ CTE
ΠΠΎΠ³Π΄Π° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ
Π Π·Π°ΠΏΡΠΎΡΠ΅ Π½Π°Π±ΡΠ°Π»ΠΈ Β«ΠΆΠΈΡΠ½ΡΡ
Β» CTE ΠΈΠ· ΡΠ°Π·Π½ΡΡ
ΡΠ°Π±Π»ΠΈΡ, Π° ΠΏΠΎΡΠΎΠΌ ΡΠ΅ΡΠΈΠ»ΠΈ ΡΠ΄Π΅Π»Π°ΡΡ ΠΌΠ΅ΠΆΠ΄Ρ Π½ΠΈΠΌΠΈ JOIN
.
ΠΠ΅ΠΉΡ Π°ΠΊΡΡΠ°Π»Π΅Π½ Π΄Π»Ρ Π²Π΅ΡΡΠΈΠΉ Π½ΠΈΠΆΠ΅ v12 ΠΈΠ»ΠΈ Π·Π°ΠΏΡΠΎΡΠΎΠ² Ρ WITH MATERIALIZED
.
ΠΠ°ΠΊ ΠΎΠΏΠΎΠ·Π½Π°ΡΡ
-> CTE Scan
&& loops > 10
&& loops Γ (rows + RRbF) > 10000
-- ΡΠ»ΠΈΡΠΊΠΎΠΌ Π±ΠΎΠ»ΡΡΠΎΠ΅ Π΄Π΅ΠΊΠ°ΡΡΠΎΠ²ΠΎ ΠΏΡΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½ΠΈΠ΅ CTE
Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΠΈ
ΠΠ½ΠΈΠΌΠ°ΡΠ΅Π»ΡΠ½ΠΎ ΠΏΡΠΎΠ°Π½Π°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°ΡΡ Π·Π°ΠΏΡΠΎΡ β Π°
#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
.
ΠΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅ Π΄Π°Π½Π½Π°Ρ ΡΠΈΡΡΠ°ΡΠΈΡ ΡΠ°ΡΠΏΠΈΡΠ°Π½Π° Π²
PostgreSQL Antipatterns: ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ° Π²ΡΠ΅ΠΌΡ Π³ΠΎΠ»ΠΎΠ²Π° .
#10: Β«ΡΡΠΎ-ΡΠΎ ΠΏΠΎΡΠ»ΠΎ Π½Π΅ ΡΠ°ΠΊΒ»
ΠΠΎΠ³Π΄Π° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ
Π‘Π»ΡΡΠΈΠ»ΠΎΡΡ ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠΈ, Π½Π°Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠΉ ΠΊΠΎΠ½ΠΊΡΡΠΈΡΡΡΡΠΈΠΌ Π·Π°ΠΏΡΠΎΡΠΎΠΌ, ΠΈΠ»ΠΈ Π½Π΅ Ρ Π²Π°ΡΠΈΠ»ΠΎ Π°ΠΏΠΏΠ°ΡΠ°ΡΠ½ΡΡ ΡΠ΅ΡΡΡΡΠΎΠ² CPU/Π³ΠΈΠΏΠ΅ΡΠ²ΠΈΠ·ΠΎΡΠ°.
ΠΠ°ΠΊ ΠΎΠΏΠΎΠ·Π½Π°ΡΡ
-> *
&& (shared hit / 8K) + (shared read / 1K) < time / 1000
-- RAM hit = 64MB/s, HDD read = 8MB/s
&& time > 100ms -- ΡΠΈΡΠ°Π»ΠΈ ΠΌΠ°Π»ΠΎ, Π½ΠΎ ΡΠ»ΠΈΡΠΊΠΎΠΌ Π΄ΠΎΠ»Π³ΠΎ
Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄Π°ΡΠΈΠΈ
ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ Π²Π½Π΅ΡΠ½ΡΡ ΡΠΈΡΡΠ΅ΠΌΡ Π΄Π»Ρ ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³Π° ΡΠ΅ΡΠ²Π΅ΡΠ° Π½Π° ΠΏΡΠ΅Π΄ΠΌΠ΅Ρ Π½Π°Π»ΠΈΡΠΈΡ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΎΠΊ ΠΈΠ»ΠΈ Π½Π΅ΡΡΠ°ΡΠ½ΠΎΠ³ΠΎ ΠΏΠΎΡΡΠ΅Π±Π»Π΅Π½ΠΈΡ ΡΠ΅ΡΡΡΡΠΎΠ². ΠΡΠΎ Π½Π°Ρ Π²Π°ΡΠΈΠ°Π½Ρ ΠΎΡΠ³Π°Π½ΠΈΠ·Π°ΡΠΈΠΈ ΡΡΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° Π΄Π»Ρ ΡΠΎΡΠ΅Π½ ΡΠ΅ΡΠ²Π΅ΡΠΎΠ² ΠΌΡ ΡΠΆΠ΅ ΡΠ°ΡΡΠΊΠ°Π·ΡΠ²Π°Π»ΠΈ
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com