ืืคื ื ืืกืคืจ ืืืืฉืื
ืืฉืชืืฉืช ืื ืืืชืจ ื-6000 ืคืขืืื ืืื, ืืื ืืืช ืืชืืื ืืช ืืฉืืืืฉืืืช ืืืื ื ืขืืื ืืขืื ืืื ืืื ืจืืืื ืืื ืืื, ืฉื ืจืืื ืืขืจื ืื:
ืืงืฉืืื ืืื ืืืืงืฉืืช ืฉืืื "ืืืคืื ืืืงืืช ืืืฉื". ๐
ืืื ืืจืฆืื ืืช, ืืฆืืื ืจืืื ืฉืืืคืืื ืืงืฉื ืืืืืช ื"ืืจืืจื ืืช" ืืืืื ืช ืืฉืืืื, ืืืคืืื ืืื ืื ืืชื ืืืืืชื ืืคื ืืืื ื ืืื ืชืื ืื ืฉื ืืชืืื ืืช.
ืืืงืจื ืื, ืื ืืคืชื ืืื ืืืืืืืืื ืื ืืฆืืจื ืืืคืฉ ืืขืฆืื ืืคืฉืจืืช ืืืคืืืืืืฆืื, ืืืกืชืื ืจืง ืขื ืื ืืกืืื ืฉืื - ื ืืื ืืกืคืจ ืื ืื ืงืืจื ืืื, ืื ืืืืื ืืืืืช ืืกืืื, ืืื ืืื ืืืืฆืื ืคืชืจืื. ืืื ืื ืฉืขืฉืื ื.
ืืืื ื ืกืชืื ืืงืจืื ืขื ืืืงืจืื ืืืื โ ืืืฆื ืื ืืืืืจืื ืืืืืื ืืืืฆืืช ืื ืืืืืืื.
ืืื ืืืชืขืืง ืืื ืืืชืจ ืื ืืฉื, ืืชื ืืืื ืงืืื ืืืืืื ืืืืืง ืืืชืืื ื
ืืก' 1: ืืื ืืงืก "ืืืื"
ืืชื ืขืืื
ืืฆื ืืช ืืืฉืืื ืืช ืืืืจืื ื ืขืืืจ ืืืงืื "LLC Kolokolchik".
ืืื ืืืืืช
-> 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)
ืืชื ืขืืื
ืืฆื ืืช ืื ืืืืืื ืขืืืจ ืืืงืื "LLC Kolokolchik" ืฉื ืืชื ืืืขื "NJSC Lyutik".
ืืื ืืืืืช
-> 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 [ืื] ืืื ืืฉืื ืฉืืืืชืืช ืืฉื ื ืขืืืจ ืื ืืื ืืืืืง ืืชื ืื 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 "ืืืงืจื" ืืืชืจ, ืืคืืื ืื ืืืฆืขื - ืืชืืฆืื ืืื ืคื 22 ืืืจ ืืืชืจ, ืคื 44 ืคืืืช ืงืจืืืืช!
ืกืืคืืจ ืืคืืจื ืืืชืจ ืขื ืฉืืืช ืืืืคืืืืืืฆืื ืืื ืขื ืืืืืืืช ืงืื ืงืจืืืืช ื ืืชื ืืงืจืื ืืืืืจืื
PostgreSQL Antipatterns: JOINs ื-ORs ืืืืงืื ะธ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. ืกืืืืกืื ืฉืื ืื ืฉื ืืืืืื/ื ืืฆื ืืชืืืืื ืืืื ืืงืืืืจืื ืื.
ืื ืืฆื ืืกืื ืื ืืืื ืืงืื ืขืจืืื ืฉืื ืื, ืขืืืฃ ืืืจืืื ืืช ืืืื ืืงืก ืขื ืืฉืืืช ืืืื - ืืื ืืืฆื ืฉื 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
ืืืืฆืืช
ืืฆืข ืืืืคื ืืื ื ืืืืคื ืงืืืข ืืืงืื [ืืื] ืื ืืืฉืื ืขืืืื ืชืืืฃ ืืกืคืืง
ืืจืื ืืืงืจืื, ืืขืืืช ืืื ื ืืจืืืช ืขื ืืื ืคืจืืกืช ืฉืืืืชื ืืงืืื ืืืฉืจ ื ืงืจืืืช ืืืืืืื ืขืกืงื, ืืืื ืืื ืฉื ืืื ื ื
PostgreSQL Antipatterns: ื ืืืืื ืืืืื ื "ืืชืื" .ืืื ืขืืื ื ืืืืื ืฉืืคืืื ืืืงืื ืืื ืื ืชืืื ืืืื ืืขืืืจ. ืืืงืจืื ืืืื, ืืืื ืืืืืจ ืืช ืืืืืืจืืชื ืืืืืืจ.
DBA: ืืืฉืจ ืืืงืื ืขืืืจ, ืื ื ืื ืงืื ืืช ืืฉืืืื ืืืืคื ืืื ื .
#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: ืืืืคื ืืืืกืง (ืืชืืืช ืืื ืืช)
ืืชื ืขืืื
ืขืืืื ืื ืคืขืื (ืืืื ืื ืืืืื) ืฉื ืืกืคืจ ืจื ืฉื ืจืฉืืืืช ืืื ื ืืชืืื ืืืืืจืื ืฉืืืงืฆื ืืื.
ืืื ืืืืืช
-> *
&& temp written > 0
ืืืืฆืืช
ืื ืืืืช ืืืืืจืื ืืืฉืืฉืช ืืช ืืคืขืืื ืืื ื ืขืืื ืืืจืื ืขื ืืขืจื ืืืืืืจ ืฉื ืืคืจืืืจ SET [LOCAL]
ืืืงืฉื/ืขืกืงื ืกืคืฆืืคืืช.
ืืืืืื:
SHOW work_mem;
-- "16MB"
SELECT
random()
FROM
generate_series(1, 1000000)
ORDER BY
1;
ืื ืื ื ืืชืงื ืื:
SET work_mem = '128MB'; -- ะฟะตัะตะด ะฒัะฟะพะปะฝะตะฝะธะตะผ ะทะฐะฟัะพัะฐ
ืืกืืืืช ืืจืืจืืช, ืื ืืฉืชืืฉืื ืจืง ืืืืืจืื ืืื ืืืืกืง, ืืฉืืืืชื ืชืืื ืืจืื ืืืชืจ ืืืืจื. ืืืงืืื, ืืืง ืืืขืืืก ืืืกืจ ืื ืืืืืกืง ืืงืฉืื.
ืืื ืื ืื ื ืืืืืื ืืืืื ืฉืื ืชืืื ืืขืืื ืื ืืืงืฆืืช ืืจืื ืืืืจืื - ืื ื ืืืฉ ืื ืืกืคืืง ืืืืื.
#9: ืกืืืืกืืืงื ืื ืจืืืื ืืืช
ืืชื ืขืืื
ืืจืื ื ืฉืคื ืืืกืืก ืืืช ืืืช, ืืื ืื ืืื ืืื ืืื ืืืจืฉ ืืืชื ANALYZE
.
ืืื ืืืืืช
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& ratio >> 10
ืืืืฆืืช
ืชืืฆืื ืืืชื ืืืจ ANALYZE
.
ืืฆื ืื ืืชืืืจ ืืืชืจ ืคืืจืื ื
PostgreSQL Antipatterns: ืืกืืืืกืืืงื ืืื ืืจืืฉ ืฉื ืืื .
#10: "ืืฉืื ืืฉืชืืฉ"
ืืชื ืขืืื
ืืืืชื ื ืขืืื ืฉืืืชืื ื ืืืงืฉื ืืชืืจื, ืื ืฉืื ืืื ืืกืคืืง ืืฉืืื ืืืืจื ืฉื CPU/Hypervisor.
ืืื ืืืืืช
-> *
&& (shared hit / 8K) + (shared read / 1K) < time / 1000
-- RAM hit = 64MB/s, HDD read = 8MB/s
&& time > 100ms -- ัะธัะฐะปะธ ะผะฐะปะพ, ะฝะพ ัะปะธัะบะพะผ ะดะพะปะณะพ
ืืืืฆืืช
ืืฉืชืืฉ ืืืฆืื ื ืืขืจืืช ื ืืืืจ ืฉืจืช ืืืกืืื ืื ืฆืจืืืช ืืฉืืืื ืืจืืื. ืืืจ ืืืืจื ื ืขื ืืืจืกื ืฉืื ื ืืืจืืื ืืชืืืื ืืื ืขืืืจ ืืืืช ืฉืจืชืื.
ืืงืืจ: www.habr.com