เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries

เป€เบกเบทเปˆเบญเบซเบฅเบฒเบเป€เบ”เบทเบญเบ™เบเปˆเบญเบ™ เบžเบงเบเป€เบฎเบปเบฒเบ›เบฐเบเบฒเบ” เบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru - เบชเบฒเบ—เบฒเบฅเบฐเบ™เบฐ เบเบฒเบ™โ€‹เบšเปโ€‹เบฅเบดโ€‹เบเบฒเบ™โ€‹เบชเปเบฒโ€‹เบฅเบฑเบšโ€‹เบเบฒเบ™โ€‹เบงเบดโ€‹เป€เบ„เบฒเบฐโ€‹เปเบฅเบฐโ€‹เบเบฒเบ™โ€‹เป€เบšเบดเปˆเบ‡โ€‹เปเบœเบ™โ€‹เบเบฒเบ™โ€‹เบชเบญเบšโ€‹เบ–เบฒเบกโ€‹ เบเบฑเบš PostgreSQL.

เบ—เปˆเบฒเบ™เป„เบ”เป‰เปƒเบŠเป‰เบกเบฑเบ™เบซเบผเบฒเบเบเบงเปˆเบฒ 6000 เป€เบ—เบทเปˆเบญเบ™เบฑเบšเบ•เบฑเป‰เบ‡เปเบ•เปˆเบ™เบฑเป‰เบ™เบกเบฒ, เปเบ•เปˆเบซเบ™เบถเปˆเบ‡เปƒเบ™เบฅเบฑเบเบชเบฐเบ™เบฐเบ—เบตเปˆเบกเบตเบ›เบฐเป‚เบซเบเบ”เบญเบฒเบ”เบˆเบฐเบšเปเปˆเป„เบ”เป‰เบชเบฑเบ‡เป€เบเบ”เป€เบซเบฑเบ™เปเบกเปˆเบ™ เบ‚เปเป‰เบ„เบถเบ”เป‚เบ„เบ‡เบชเป‰เบฒเบ‡, เบŠเบถเปˆเบ‡โ€‹เป€เบšเบดเปˆเบ‡โ€‹เบ„เบทโ€‹เปเบ™เบงโ€‹เบ™เบตเป‰โ€‹:

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries

เบŸเบฑเบ‡เบžเบงเบเป€เบ‚เบปเบฒเปเบฅเบฐเบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเบ‚เบญเบ‡เบ—เปˆเบฒเบ™เบˆเบฐ "เบเบฒเบเป€เบ›เบฑเบ™เบเป‰เบฝเบ‡". ๐Ÿ™‚

เปเบ•เปˆเบขเปˆเบฒเบ‡เบˆเบดเบ‡เบˆเบฑเบ‡, เบซเบผเบฒเบเบชเบฐเบ–เบฒเบ™เบฐเบเบฒเบ™เบ—เบตเปˆเป€เบฎเบฑเบ”เปƒเบซเป‰เบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เปเบŠเป‰เบฒเปเบฅเบฐ "gluttonous" เปƒเบ™เปเบ‡เปˆเบ‚เบญเบ‡เบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™, เปเบกเปˆเบ™เบ›เบปเบเบเบฐเบ•เบดเปเบฅเบฐเบชเบฒเบกเบฒเบ”เบฎเบฑเบšเบฎเบนเป‰เป„เบ”เป‰เป‚เบ”เบเป‚เบ„เบ‡เบชเป‰เบฒเบ‡เปเบฅเบฐเบ‚เปเป‰เบกเบนเบ™เบ‚เบญเบ‡เปเบœเบ™เบเบฒเบ™.

เปƒเบ™เบเปเบฅเบฐเบ™เบตเบ™เบตเป‰, เบ™เบฑเบเบžเบฑเบ”เบ—เบฐเบ™เบฒเปเบ•เปˆเบฅเบฐเบ„เบปเบ™เบˆเบฐเบšเปเปˆเบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เบŠเบญเบเบซเบฒเบ—เบฒเบ‡เป€เบฅเบทเบญเบเบเบฒเบ™เป€เบžเบตเปˆเบกเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบ‚เบญเบ‡เบ•เบปเบ™เป€เบญเบ‡, เบญเบตเบ‡เปƒเบชเปˆเบ›เบฐเบชเบปเบšเบเบฒเบ™เบ‚เบญเบ‡เบ•เบปเบ™เป€เบญเบ‡เป€เบ—เบปเปˆเบฒเบ™เบฑเป‰เบ™ - เบžเบงเบเป€เบฎเบปเบฒเบชเบฒเบกเบฒเบ”เบšเบญเบเบฅเบฒเบงเบงเปˆเบฒเบชเบดเปˆเบ‡เบ—เบตเปˆเป€เบเบตเบ”เบ‚เบทเป‰เบ™เบขเบนเปˆเบ—เบตเปˆเบ™เบตเป‰, เป€เบซเบ”เบœเบปเบ™เปเบกเปˆเบ™เบซเบเบฑเบ‡, เปเบฅเบฐ. เบˆเบฐเบกเบฒเป€เบ–เบดเบ‡เบกเบตเบเบฒเบ™เปเบเป‰เป„เบ‚เปเบ™เบงเปƒเบ”. เป€เบŠเบดเปˆเบ‡เป€เบ›เบฑเบ™เบชเบดเปˆเบ‡เบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เป€เบฎเบฑเบ”.

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries

เบ‚เปเปƒเบซเป‰เบžเบดเบˆเบฒเบฅเบฐเบ™เบฒเบขเปˆเบฒเบ‡เบฅเบฐเบญเบฝเบ”เบเปˆเบฝเบงเบเบฑเบšเบเปเบฅเบฐเบ™เบตเป€เบซเบผเบปเปˆเบฒเบ™เบตเป‰ - เบงเบดเบ—เบตเบเบฒเบ™เบ—เบตเปˆเบžเบงเบเป€เบ‚เบปเบฒเบ–เบทเบเบเปเบฒเบ™เบปเบ”เปเบฅเบฐเบ„เปเบฒเปเบ™เบฐเบ™เปเบฒเปƒเบ”เบ—เบตเปˆเป€เบ‚เบปเบฒเป€เบˆเบปเป‰เบฒเบ™เปเบฒเป„เบ›เบชเบนเปˆ.

เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™ immersion เบ—เบตเปˆเบ”เบตเบเบงเปˆเบฒเปƒเบ™เบซเบปเบงเบ‚เปเป‰, เบ—เปเบฒเบญเบดเบ”เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบŸเบฑเบ‡เบ•เบฑเบ™เบ—เบตเปˆเบชเบญเบ”เบ„เป‰เบญเบ‡เบเบฑเบ™เบˆเบฒเบ เบšเบปเบ”เบฅเบฒเบเบ‡เบฒเบ™เบ‚เบญเบ‡เบ‚เป‰เบญเบเบขเบนเปˆ PGConf.Russia 2020, เปเบฅเบฐเบžเบฝเบ‡เปเบ•เปˆเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เป„เบ›เบซเบฒเบเบฒเบ™เบงเบดเป€เบ„เบฒเบฐเบฅเบฒเบเบฅเบฐเบญเบฝเบ”เบ‚เบญเบ‡เปเบ•เปˆเบฅเบฐเบ•เบปเบงเบขเปˆเบฒเบ‡:

#1: เบ”เบฑเบ”เบชเบฐเบ™เบต "undersorting"

เป€เบกเบทเปˆเบญโ€‹เป€เบเบตเบ”โ€‹เบ‚เบถเป‰เบ™

เบชเบฐเปเบ”เบ‡เปƒเบšเป€เบเบฑเบšเป€เบ‡เบดเบ™เบชเบธเบ”เบ—เป‰เบฒเบเบชเปเบฒเบฅเบฑเบšเบฅเบนเบเบ„เป‰เบฒ "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;

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบชเบฑเบ‡เป€เบเบ”เป€เบซเบฑเบ™เป„เบ”เป‰เบ—เบฑเบ™เบ—เบตเบงเปˆเบฒเบซเบผเบฒเบเบเบงเปˆเบฒ 100 เบšเบฑเบ™เบ—เบถเบเป„เบ”เป‰เบ–เบทเบเบซเบฑเบเบญเบญเบเป‚เบ”เบเบ”เบฑเบ”เบŠเบฐเบ™เบต, เป€เบŠเบดเปˆเบ‡เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เป„เบ”เป‰เบ–เบทเบเบˆเบฑเบ”เบฎเบฝเบ‡เบ—เบฑเบ‡เบซเบกเบปเบ”, เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบžเบฝเบ‡เปเบ•เปˆเบซเบ™เบถเปˆเบ‡เบญเบฑเบ™เบ”เบฝเบงเบ—เบตเปˆเบ–เบทเบเบ›เบฐเป„เบงเป‰.

เบžเบงเบเป€เบฎเบปเบฒเปเบเป‰เป„เบ‚:

DROP INDEX tbl_fk_cli_idx;
CREATE INDEX ON tbl(fk_cli, pk DESC); -- ะดะพะฑะฐะฒะธะปะธ ะบะปัŽั‡ ัะพั€ั‚ะธั€ะพะฒะบะธ

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒเบขเบนเปˆเปƒเบ™เบ•เบปเบงเบขเปˆเบฒเบ‡เป€เบšเบทเป‰เบญเบ‡เบ•เบปเป‰เบ™เบ”เบฑเปˆเบ‡เบเปˆเบฒเบง - เป„เบงเบเบงเปˆเบฒ 8.5x เปเบฅเบฐเบญเปˆเบฒเบ™เปœเป‰เบญเบเบฅเบปเบ‡ 33x. เบœเบปเบ™เบเบฐเบ—เบปเบšเบˆเบฐเบŠเบฑเบ”เป€เบˆเบ™เบเบงเปˆเบฒ, เบซเบผเบฒเบ "เบ„เบงเบฒเบกเบˆเบดเบ‡" เบ—เปˆเบฒเบ™เบกเบตเบชเปเบฒเบฅเบฑเบšเปเบ•เปˆเบฅเบฐเบกเบนเบ™เบ„เปˆเบฒ. 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); -- ะพั‚ะฑะพั€ ะฟะพ ะบะพะฝะบั€ะตั‚ะฝะพะน ะฟะฐั€ะต

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบžเบงเบเป€เบฎเบปเบฒเปเบเป‰เป„เบ‚:

DROP INDEX tbl_fk_org_idx;
CREATE INDEX ON tbl(fk_org, fk_cli);

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เปƒเบ™เบ—เบตเปˆเบ™เบตเป‰เบœเบปเบ™เบ›เบฐเป‚เบซเบเบ”เปเบกเปˆเบ™เบ™เป‰เบญเบเบฅเบปเบ‡, เบ™เบฑเบšเบ•เบฑเป‰เบ‡เปเบ•เปˆ Bitmap Heap Scan เปเบกเปˆเบ™เบ‚เป‰เบญเบ™เบ‚เป‰เบฒเบ‡เบกเบตเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบ‚เบญเบ‡เบกเบฑเบ™เป€เบญเบ‡. เปเบ•เปˆเบขเปˆเบฒเบ‡เปƒเบ”เบเปเปˆเบ•เบฒเบก เป„เบงเบเบงเปˆเบฒ 7x เปเบฅเบฐเบญเปˆเบฒเบ™เปœเป‰เบญเบเบฅเบปเบ‡ 2.5x.

#3: เบเบฒเบ™เบฅเบงเบกเบ”เบฑเบ”เบŠเบฐเบ™เบต (BitmapOr)

เป€เบกเบทเปˆเบญโ€‹เป€เบเบตเบ”โ€‹เบ‚เบถเป‰เบ™

เบชเบฐเปเบ”เบ‡เปƒเบซเป‰เป€เบซเบฑเบ™ 20 เบ—เปเบฒเบญเบดเบ”เบ—เบตเปˆเป€เบเบปเปˆเบฒเปเบเปˆเบ—เบตเปˆเบชเบธเบ” "เบ‚เบญเบ‡เบ•เบปเบ™เป€เบญเบ‡" เบซเบผเบทเบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เปเบ—เบตเปˆเบšเปเปˆเป„เบ”เป‰เบกเบญเบšเบซเบกเบฒเบเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ›เบฐเบกเบงเบ™เบœเบปเบ™, เบ‚เบญเบ‡เบ•เบปเบ™เป€เบญเบ‡เปƒเบ™เบšเบนเบฅเบดเบกเบฐเบชเบดเบ”.

เบงเบดเบ—เบตเบเบฒเบ™เบเปเบฒเบ™เบปเบ”

-> BitmapOr
   -> Bitmap Index Scan
   -> Bitmap Index Scan

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เปƒเบŠเป‰ เบชเบฐเบซเบฐเบžเบฑเบ™ [เบ—เบฑเบ‡เปเบปเบ”] เป€เบžเบทเปˆเบญเบชเบปเบกเบ—เบปเบšเบเบฒเบ™เบชเบญเบšเบ–เบฒเบกเบเปˆเบญเบเบชเปเบฒเบฅเบฑเบšเปเบ•เปˆเบฅเบฐเป€เบ‡เบทเปˆเบญเบ™เป„เบ‚ 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;

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบžเบงเบเป€เบฎเบปเบฒเปเบเป‰เป„เบ‚:

(
  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, ะฑะพะปัŒัˆะต ะธ ะฝะต ะฝะฐะดะพ

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เปƒเบŠเป‰เบ›เบฐเป‚เบเบ”เบˆเบฒเบเบ„เบงเบฒเบกเบˆเบดเบ‡เบ—เบตเปˆเบงเปˆเบฒเบšเบฑเบ™เบ—เบถเบเบ—เบตเปˆเบˆเปเบฒเป€เบ›เบฑเบ™เบ—เบฑเบ‡เบซเบกเบปเบ” 20 เป„เบ”เป‰เบ–เบทเบเป„เบ”เป‰เบฎเบฑเบšเบ—เบฑเบ™เบ—เบตเปƒเบ™เบ—เปˆเบญเบ™เป„เบกเป‰เบ—เปเบฒเบญเบดเบ”, เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™เบญเบฑเบ™เบ—เบตเบชเบญเบ‡, เบ”เป‰เบงเบเบเบฒเบ™เบชเบฐเปเบเบ™ Bitmap Heap "เบฅเบฒเบ„เบฒเปเบžเบ‡เบเบงเปˆเบฒ", เบšเปเปˆเป„เบ”เป‰เบ–เบทเบเบ›เบฐเบ•เบดเบšเบฑเบ” - เบ”เบฑเปˆเบ‡เบ™เบฑเป‰เบ™. เป„เบงเบเบงเปˆเบฒ 22x, เบญเปˆเบฒเบ™เปœเป‰เบญเบเบฅเบปเบ‡ 44x!

เป€เบฅเบทเปˆเบญเบ‡เบฅเบฒเบเบฅเบฐเบญเบฝเบ”เป€เบžเบตเปˆเบกเป€เบ•เบตเบกเบเปˆเบฝเบงเบเบฑเบšเบงเบดเบ—เบตเบเบฒเบ™เป€เบžเบตเปˆเบกเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบ™เบตเป‰ เบเปˆเบฝเบงเบเบฑเบšเบ•เบปเบงเบขเปˆเบฒเบ‡เบ—เบตเปˆเบŠเบฑเบ”เป€เบˆเบ™ เบชเบฒเบกเบฒเบ”เบญเปˆเบฒเบ™เป„เบ”เป‰เปƒเบ™เบšเบปเบ”เบ„เบงเบฒเบก PostgreSQL Antipatterns: เบเบฒเบ™เป€เบ‚เบปเป‰เบฒเบฎเปˆเบงเบกเบ—เบตเปˆเป€เบ›เบฑเบ™เบญเบฑเบ™เบ•เบฐเบฅเบฒเบ เปเบฅเบฐ ORs ะธ PostgreSQL Antipatterns: เบ™เบดเบ—เบฒเบ™เป€เบฅเบทเปˆเบญเบ‡เบ‚เบญเบ‡เบเบฒเบ™เบ›เบฑเบšเบ›เบธเบ‡เปƒเบซเบกเปˆเบ‚เบญเบ‡เบเบฒเบ™เบ„เบปเป‰เบ™เบซเบฒเป‚เบ”เบเบŠเบทเปˆ, เบซเบผเบท "เบเบฒเบ™เป€เบžเบตเปˆเบกเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบšเบเบฑเบšเบ„เบทเบ™เป„เบ›เบšเปˆเบญเบ™เปเบฅเบฐเบญเบญเบเป„เบ›".

เบชเบฐเบšเบฑเบšเบ—เบปเปˆเบงเป„เบ› เบชเบฑเปˆเบ‡เป€เบฅเบทเบญเบเบ”เป‰เบงเบเบซเบผเบฒเบเบ›เบธเปˆเบก (เปเบฅเบฐเบšเปเปˆเบžเบฝเบ‡เปเบ•เปˆเบชเปเบฒเบฅเบฑเบšเบ„เบนเปˆเบ‚เบญเบ‡ const / NULL) เปเบกเปˆเบ™เบชเบปเบ™เบ—เบฐเบ™เบฒเปƒเบ™เบšเบปเบ”เบ„เบงเบฒเบก SQL HowTo: เบ‚เบฝเบ™ while-loop เป‚เบ”เบเบเบปเบ‡เปƒเบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบก, เบซเบผเบท "เบ›เบฐเบ–เบปเบกเบชเบฒเบกเบ—เบฒเบ‡".

#4: เบžเบงเบเป€เบฎเบปเบฒเบญเปˆเบฒเบ™เบซเบผเบฒเบเป€เบเบตเบ™เป„เบ›

เป€เบกเบทเปˆเบญโ€‹เป€เบเบตเบ”โ€‹เบ‚เบถเป‰เบ™

เบ•เบฒเบกเบเบปเบ”เบฅเบฐเบšเบฝเบš, เบกเบฑเบ™เป€เบเบตเบ”เบ‚เบทเป‰เบ™เปƒเบ™เป€เบงเบฅเบฒเบ—เบตเปˆเบ—เปˆเบฒเบ™เบ•เป‰เบญเบ‡เบเบฒเบ™ "เปเบ™เบšเบ•เบปเบงเบเบญเบ‡เบญเบทเปˆเบ™" เบเบฑเบšเบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเบ—เบตเปˆเบกเบตเบขเบนเปˆ.

"เปเบฅเบฐเป€เบˆเบปเป‰เบฒเบšเปเปˆเบกเบตเบ„เบทเบเบฑเบ™, เปเบ•เปˆ เบกเบตเบ›เบธเปˆเบกเป„เบ‚เปˆเบกเบธเบ? ยป เบฎเบนเบšเป€เบ‡เบปเบฒ "เบกเบทเป€เบžเบฑเบ”"

เบ•เบปเบงเบขเปˆเบฒเบ‡, เบเบฒเบ™เปเบเป‰เป„เบ‚เบงเบฝเบเบ‡เบฒเบ™เบ‚เป‰เบฒเบ‡เป€เบ—เบดเบ‡, เบชเบฐเปเบ”เบ‡เปƒเบซเป‰เป€เบซเบฑเบ™ 20 เบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เป "เบชเปเบฒเบ„เบฑเบ™" เบ—เบตเปˆเป€เบเบปเปˆเบฒเปเบเปˆเบ—เบตเปˆเบชเบธเบ”เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ›เบธเบ‡เปเบ•เปˆเบ‡, เป‚เบ”เบเบšเปเปˆเบ„เปเบฒเบ™เบถเบ‡เป€เบ–เบดเบ‡เบˆเบธเบ”เบ›เบฐเบชเบปเบ‡เบ‚เบญเบ‡เบžเบงเบเป€เบ‚เบปเบฒ.

เบงเบดเบ—เบตเบเบฒเบ™เบเปเบฒเบ™เบปเบ”

-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
   && 5 ร— rows < RRbF -- ะพั‚ั„ะธะปัŒั‚ั€ะพะฒะฐะฝะพ >80% ะฟั€ะพั‡ะธั‚ะฐะฝะฝะพะณะพ
   && loops ร— RRbF > 100 -- ะธ ะฟั€ะธ ัั‚ะพะผ ะฑะพะปัŒัˆะต 100 ะทะฐะฟะธัะตะน ััƒะผะผะฐั€ะฝะพ

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เบชเป‰เบฒเบ‡ [เป€เบžเบตเปˆเบกเป€เบ•เบตเบก] เบžเบดเป€เบชเบ” index เบเบฑเบš WHERE clause เบซเบผเบทเบฅเบงเบกเป€เบญเบปเบฒเบŠเปˆเบญเบ‡เบ‚เปเป‰เบกเบนเบ™เป€เบžเบตเปˆเบกเป€เบ•เบตเบกเปƒเบ™เบ”เบฑเบ”เบŠเบฐเบ™เบต.

เบ–เป‰เบฒเป€เบ‡เบทเปˆเบญเบ™เป„เบ‚เบเบฒเบ™เบเบฑเปˆเบ™เบ•เบญเบ‡เปเบกเปˆเบ™ "static" เบชเปเบฒเบฅเบฑเบšเบงเบฝเบเบ‡เบฒเบ™เบ‚เบญเบ‡เบ—เปˆเบฒเบ™ - เบ™เบฑเป‰เบ™เปเบกเปˆเบ™ เบšเปเปˆเบฅเบงเบกเบเบฒเบ™เบ‚เบฐเบซเบเบฒเบ เบšเบฑเบ™เบŠเบตเบฅเบฒเบเบŠเบทเปˆเบ‚เบญเบ‡เบกเบนเบ™เบ„เปˆเบฒเปƒเบ™เบญเบฐเบ™เบฒเบ„เบปเบ” - เบกเบฑเบ™เบ”เบตเบเบงเปˆเบฒเบ—เบตเปˆเบˆเบฐเปƒเบŠเป‰เบ”เบฑเบ”เบชเบฐเบ™เบต 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;

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบžเบงเบเป€เบฎเบปเบฒเปเบเป‰เป„เบ‚:

CREATE INDEX ON tbl(pk)
  WHERE critical; -- ะดะพะฑะฐะฒะธะปะธ "ัั‚ะฐั‚ะธั‡ะฝะพะต" ัƒัะปะพะฒะธะต ั„ะธะปัŒั‚ั€ะฐั†ะธะธ

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบ”เบฑเปˆเบ‡เบ—เบตเปˆเบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เป€เบซเบฑเบ™เป„เบ”เป‰, เบเบฒเบ™เบเบฑเปˆเบ™เบ•เบญเบ‡เบˆเบฒเบเปเบœเบ™เบเบฒเบ™เปเบกเปˆเบ™เบซเบกเบปเบ”เป„เบ›, เปเบฅเบฐเบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เปเป„เบ”เป‰เบเบฒเบเป€เบ›เบฑเบ™ เป„เบงเบเบงเปˆเบฒ 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

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เบ›เบฐเบ•เบดเบšเบฑเบ”เบ”เป‰เบงเบเบ•เบปเบ™เป€เบญเบ‡เป€เบ›เบฑเบ™เบ›เบปเบเบเบฐเบ•เบด เบชเบนเบ™เบเบฒเบเบฒเบ” [FULL] เบซเบผเบทเบšเบฑเบ™เบฅเบธเบเบฒเบ™เบ›เบธเบ‡เปเบ•เปˆเบ‡เป€เบฅเบทเป‰เบญเบเป†เบขเปˆเบฒเบ‡เบžเบฝเบ‡เบžเป เบญเบฑเบ”เบ•เบฐเป‚เบ™เบกเบฑเบ” เป‚เบ”เบเบเบฒเบ™เบ›เบฑเบšเบ›เบธเบ‡เบ•เบปเบงเบเปเบฒเบ™เบปเบ”เบเบฒเบ™เบ‚เบญเบ‡เบกเบฑเบ™, เบฅเบงเบกเบ—เบฑเบ‡ เบชเปเบฒเบฅเบฑเบšเบ•เบฒเบ•เบฐเบฅเบฒเบ‡เบชเบฐเป€เบžเบฒเบฐ.

เปƒเบ™เบเปเบฅเบฐเบ™เบตเบซเบผเบฒเบเบ—เบตเปˆเบชเบธเบ”, เบšเบฑเบ™เบซเบฒเบ”เบฑเปˆเบ‡เบเปˆเบฒเบงเปเบกเปˆเบ™เป€เบเบตเบ”เบกเบฒเบˆเบฒเบเบฎเบนเบšเปเบšเบšเบเบฒเบ™เบชเบญเบšเบ–เบฒเบกเบ—เบตเปˆเบšเปเปˆเบ”เบตเป€เบกเบทเปˆเบญเบ–เบทเบเป€เบญเบตเป‰เบ™เบˆเบฒเบเป€เบซเบ”เบœเบปเบ™เบ—เบฒเบ‡เบ—เบธเบฅเบฐเบเบดเบ”, เป€เบŠเบฑเปˆเบ™เบงเปˆเบฒเบเบฒเบ™เบชเบปเบ™เบ—เบฐเบ™เบฒเปƒเบ™. PostgreSQL Antipatterns: เบ•เปเปˆเบชเบนเป‰เบเบฑเบš hordes เบ‚เบญเบ‡ "เบ•เบฒเบ".

เปเบ•เปˆเบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เป€เบ‚เบปเป‰เบฒเปƒเบˆเบงเปˆเบฒเป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒ VACUUM FULL เบเปเปˆเบšเปเปˆเบชเบฒเบกเบฒเบ”เบŠเปˆเบงเบเป„เบ”เป‰เบชเบฐเป€เปเบต. เบชเปเบฒเบฅเบฑเบšเบเปเบฅเบฐเบ™เบตเบ”เบฑเปˆเบ‡เบเปˆเบฒเบง, เบ—เปˆเบฒเบ™เบ„เบงเบ™เบ„เบธเป‰เบ™เป€เบ„เบตเบเบเบฑเบš algorithm เบˆเบฒเบเบšเบปเบ”เบ„เบงเบฒเบก. DBA: เป€เบกเบทเปˆเบญ VACUUM เบœเปˆเบฒเบ™เป„เบ›, เบžเบงเบเป€เบฎเบปเบฒเป€เบฎเบฑเบ”เบ„เบงเบฒเบกเบชเบฐเบญเบฒเบ”เบ•เบฒเบ•เบฐเบฅเบฒเบ‡เบ”เป‰เบงเบเบ•เบปเบ™เป€เบญเบ‡.

#6: เบญเปˆเบฒเบ™เบˆเบฒเบ "เบเบฒเบ‡" เบ‚เบญเบ‡เบ”เบฑเบ”เบŠเบฐเบ™เบต

เป€เบกเบทเปˆเบญโ€‹เป€เบเบตเบ”โ€‹เบ‚เบถเป‰เบ™

เบกเบฑเบ™เป€เบšเบดเปˆเบ‡เบ„เบทเบงเปˆเบฒเบžเบงเบเป€เบ‚เบปเบฒเบญเปˆเบฒเบ™เป€เบฅเบฑเบเบ™เป‰เบญเบ, เปเบฅเบฐเบ—เบธเบเบชเบดเปˆเบ‡เบ—เบธเบเบขเปˆเบฒเบ‡เป„เบ”เป‰เบ–เบทเบเบ”เบฑเบ”เบชเบฐเบ™เบต, เปเบฅเบฐเบžเบงเบเป€เบ‚เบปเบฒเบšเปเปˆเป„เบ”เป‰เบเบฑเปˆเบ™เบ•เบญเบ‡เปƒเบœเป€เบžเบตเปˆเบกเป€เบ•เบตเบก - เปเบ•เปˆเบเบฑเบ‡เบกเบตเบซเบ™เป‰เบฒเบซเบผเบฒเบเบซเบผเบฒเบเบ—เบตเปˆเบญเปˆเบฒเบ™เบซเบผเบฒเบเบเบงเปˆเบฒเบ—เบตเปˆเบžเบงเบเป€เบฎเบปเบฒเบ•เป‰เบญเบ‡เบเบฒเบ™.

เบงเบดเบ—เบตเบเบฒเบ™เบเปเบฒเบ™เบปเบ”

-> Index [Only] Scan [Backward]
   && loops ร— (rows + RRbF) < (shared hit + shared read) ร— 8
      -- ะฟั€ะพั‡ะธั‚ะฐะฝะพ ะฑะพะปัŒัˆะต 1KB ะฝะฐ ะบะฐะถะดัƒัŽ ะทะฐะฟะธััŒ
   && shared hit + shared read > 64

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เบเบงเบ”เป€เบšเบดเปˆเบ‡เป‚เบ„เบ‡เบชเป‰เบฒเบ‡เบ‚เบญเบ‡เบ”เบฑเบ”เบŠเบฐเบ™เบตเบ—เบตเปˆเบ™เปเบฒเปƒเบŠเป‰เปเบฅเบฐเบžเบฒเบเบชเบฐเบซเบ™เบฒเบกเบ—เบตเปˆเบชเปเบฒเบ„เบฑเบ™เบ—เบตเปˆเบฅเบฐเบšเบธเป„เบงเป‰เปƒเบ™เปเบšเบšเบชเบญเบšเบ–เบฒเบก - เบชเปˆเบงเบ™เบซเบผเบฒเบเบญเบฒเบ”เบˆเบฐ, เบชเปˆเบงเบ™เบ”เบฑเบ”เบชเบฐเบ™เบตเบšเปเปˆเป„เบ”เป‰เบ•เบฑเป‰เบ‡. เบชเปˆเบงเบ™เบซเบผเบฒเบเป€เบˆเบปเป‰เบฒเบˆเบฐเบ•เป‰เบญเบ‡เบชเป‰เบฒเบ‡เบ”เบฑเบ”เบชเบฐเบ™เบตเบ—เบตเปˆเบ„เป‰เบฒเบเบ„เบทเบเบฑเบ™, เปเบ•เปˆเบšเปเปˆเบกเบต prefix fields, เบซเบผเบท เบฎเบฝเบ™เบฎเบนเป‰เบ—เบตเปˆเบˆเบฐ iterate เบ„เบธเบ™เบ„เปˆเบฒเบ‚เบญเบ‡เป€เบ‚เบปเบฒเป€เบˆเบปเป‰เบฒ.

เบ•เบปเบงเบขเปˆเบฒเบ‡:

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;

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบ—เบธเบเบขเปˆเบฒเบ‡เป€เบšเบดเปˆเบ‡เบ„เบทเบงเปˆเบฒเบ”เบต, เป€เบ–เบดเบ‡เปเบกเปˆเบ™เบงเปˆเบฒเปƒเบ™เปเบ‡เปˆเบ‚เบญเบ‡เบ”เบฑเบ”เบชเบฐเบ™เบต, เปเบ•เปˆเบกเบตเบ„เบงเบฒเบกเบชเบปเบ‡เปƒเบชเบšเบฒเบ‡เบขเปˆเบฒเบ‡ - เบชเปเบฒเบฅเบฑเบšเปเบ•เปˆเบฅเบฐเบšเบฑเบ™เบ—เบถเบ 20 เบ—เบตเปˆเบญเปˆเบฒเบ™, 4 เบซเบ™เป‰เบฒเบ‚เบญเบ‡เบ‚เปเป‰เบกเบนเบ™เบ•เป‰เบญเบ‡เบ–เบทเบเบซเบฑเบเบญเบญเบ, 32KB เบ•เปเปˆเบšเบฑเบ™เบ—เบถเบ - เบกเบฑเบ™เบšเปเปˆเบเป‰เบฒเบซเบฒเบ™เบšเป? เปเบกเปˆเบ™เปเบฅเบฐเบŠเบทเปˆเบ”เบฑเบ”เบชเบฐเบ™เบต tbl_fk_org_fk_cli_idx เบ™เปเบฒเป„เบ›เบชเบนเปˆเบ„เบงเบฒเบกเบ„เบดเบ”.

เบžเบงเบเป€เบฎเบปเบฒเปเบเป‰เป„เบ‚:

CREATE INDEX ON tbl(fk_cli);

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบ—เบฑเบ™โ€‹เบ—เบตโ€‹เบ—เบฑเบ™โ€‹เปƒเบ” - เป„เบงเบเบงเปˆเบฒ 10 เป€เบ—เบปเปˆเบฒ เปเบฅเบฐเบญเปˆเบฒเบ™เปœเป‰เบญเบเบฅเบปเบ‡ 4 เป€เบ—เบปเปˆเบฒ!

เบชเปเบฒเบฅเบฑเบšเบ•เบปเบงเบขเปˆเบฒเบ‡เป€เบžเบตเปˆเบกเป€เบ•เบตเบกเบ‚เบญเบ‡เบเบฒเบ™เบ™เปเบฒเปƒเบŠเป‰เบ”เบฑเบ”เบชเบฐเบ™เบตเบ—เบตเปˆเบšเปเปˆเบกเบตเบ›เบฐเบชเบดเบ”เบ—เบดเบžเบฒเบš, เป€เบšเบดเปˆเบ‡เบšเบปเบ”เบ„เบงเบฒเบก DBA: เบŠเบญเบเบซเบฒเบ”เบฑเบ”เบชเบฐเบ™เบตเบ—เบตเปˆเบšเปเปˆเบกเบตเบ›เบฐเป‚เบซเบเบ”.

#7: CTE ร— CTE

เป€เบกเบทเปˆเบญโ€‹เป€เบเบตเบ”โ€‹เบ‚เบถเป‰เบ™

เปƒเบ™เบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เป เป„เบ”เป‰เบ„เบฐเปเบ™เบ™ "เป„เบ‚เบกเบฑเบ™" CTE เบˆเบฒเบเบ•เบฒเบ•เบฐเบฅเบฒเบ‡เบ—เบตเปˆเปเบ•เบเบ•เปˆเบฒเบ‡เบเบฑเบ™, เปเบฅเบฐเบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบ•เบฑเบ”เบชเบดเบ™เปƒเบˆเป€เบฎเบฑเบ”เบฅเบฐเบซเบงเปˆเบฒเบ‡เป€เบ‚เบปเบฒเป€เบˆเบปเป‰เบฒ JOIN.

เบเปโ€‹เบฅเบฐโ€‹เบ™เบตโ€‹เบ—เบตเปˆโ€‹เบเปˆเบฝเบงโ€‹เบ‚เป‰เบญเบ‡โ€‹เบชเปเบฒโ€‹เบฅเบฑเบšโ€‹เบเบฒเบ™โ€‹เบชเบฐโ€‹เบšเบฑเบšโ€‹เบ‚เป‰เบฒเบ‡โ€‹เบฅเบธเปˆเบกโ€‹เบ™เบตเป‰ v12 เบซเบผเบทโ€‹เบเบฒเบ™โ€‹เบฎเป‰เบญเบ‡โ€‹เบ‚เปโ€‹เบเบฑเบšโ€‹ WITH MATERIALIZED.

เบงเบดเบ—เบตเบเบฒเบ™เบเปเบฒเบ™เบปเบ”

-> CTE Scan
   && loops > 10
   && loops ร— (rows + RRbF) > 10000
      -- ัะปะธัˆะบะพะผ ะฑะพะปัŒัˆะพะต ะดะตะบะฐั€ั‚ะพะฒะพ ะฟั€ะพะธะทะฒะตะดะตะฝะธะต CTE

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เบงเบดเป€เบ„เบฒเบฐเบ„เปเบฒเบฎเป‰เบญเบ‡เบ‚เปเบขเปˆเบฒเบ‡เบฅเบฐเบญเบฝเบ” CTEs เบกเบตเบ„เบงเบฒเบกเบˆเปเบฒเป€เบ›เบฑเบ™เบขเบนเปˆเบ—เบตเปˆเบ™เบตเป‰เบ—เบฑเบ‡เบซเบกเบปเบ”? เบ–เป‰เบฒเปเบกเปˆเบ™, เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™ เบ™เบณเปƒเบŠเป‰ "เบงเบฑเบ”เบˆเบฐเบ™เบฒเบ™เบธเบเบปเบก" เปƒเบ™ hstore/json เบญเบตเบ‡เบ•เบฒเบกเบ•เบปเบงเปเบšเบšเบ—เบตเปˆเป„เบ”เป‰เบญเบฐเบ—เบดเบšเบฒเบเป„เบงเป‰เปƒเบ™ PostgreSQL Antipatterns: Dictionary Hit Heavy JOIN.

#8: swap to disk ( temp เบ‚เบฝเบ™โ€‹)

เป€เบกเบทเปˆเบญโ€‹เป€เบเบตเบ”โ€‹เบ‚เบถเป‰เบ™

เบเบฒเบ™เบ›เบฐเบกเบงเบ™เบœเบปเบ™เบ„เบฑเป‰เบ‡เบ”เบฝเบง (เบเบฒเบ™เบˆเบฑเบ”เบฎเบฝเบ‡เบซเบผเบทเบเบฒเบ™เป€เบ›เบฑเบ™เป€เบญเบเบฐเบฅเบฑเบ) เบ‚เบญเบ‡เบšเบฑเบ™เบ—เบถเบเบˆเปเบฒเบ™เบงเบ™เบซเบฅเบฒเบเบšเปเปˆเป€เบซเบกเบฒเบฐเบชเบปเบกเบเบฑเบšเบซเบ™เปˆเบงเบเบ„เบงเบฒเบกเบˆเปเบฒเบ—เบตเปˆเบˆเบฑเบ”เบชเบฑเบ™เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบ™เบตเป‰.

เบงเบดเบ—เบตเบเบฒเบ™เบเปเบฒเบ™เบปเบ”

-> *
   && temp written > 0

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เบ–เป‰เบฒเบˆเปเบฒเบ™เบงเบ™เบซเบ™เปˆเบงเบเบ„เบงเบฒเบกเบˆเปเบฒเบ—เบตเปˆเปƒเบŠเป‰เป‚เบ”เบเบเบฒเบ™เบ”เปเบฒเป€เบ™เบตเบ™เบ‡เบฒเบ™เบšเปเปˆเป€เบเบตเบ™เบกเบนเบ™เบ„เปˆเบฒเบ—เบตเปˆเบเปเบฒเบ™เบปเบ”เป„เบงเป‰เบ‚เบญเบ‡เบžเบฒเบฅเบฒเบกเบดเป€เบ•เบต work_mem, เบกเบฑเบ™เบ„เบงเบ™เบˆเบฐเบ–เบทเบเปเบเป‰เป„เบ‚. เบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบ—เบฑเบ™เบ—เบตเปƒเบ™เบเบฒเบ™เบ•เบฑเป‰เบ‡เบ„เปˆเบฒเบชเปเบฒเบฅเบฑเบšเบ—เบธเบเบ„เบปเบ™, เบซเบผเบทเบ—เปˆเบฒเบ™เบชเบฒเบกเบฒเบ”เบœเปˆเบฒเบ™ SET [LOCAL] เบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบฎเป‰เบญเบ‡เบ‚เป / เบเบฒเบ™เป€เบฎเบฑเบ”เบ—เบธเบฅเบฐเบเปเบฒเบชเบฐเป€เบžเบฒเบฐ.

เบ•เบปเบงเบขเปˆเบฒเบ‡:

SHOW work_mem;
-- "16MB"

SELECT
  random()
FROM
  generate_series(1, 1000000)
ORDER BY
  1;

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบžเบงเบเป€เบฎเบปเบฒเปเบเป‰เป„เบ‚:

SET work_mem = '128MB'; -- ะฟะตั€ะตะด ะฒั‹ะฟะพะปะฝะตะฝะธะตะผ ะทะฐะฟั€ะพัะฐ

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
[เป€เบšเบดเปˆเบ‡เบ—เบตเปˆเบญเบฐเบ—เบดเบšเบฒเบ.tensor.ru]

เบชเปเบฒเบฅเบฑเบšเป€เบซเบ”เบœเบปเบ™เบ—เบตเปˆเบŠเบฑเบ”เป€เบˆเบ™, เบ–เป‰เบฒเบžเบฝเบ‡เปเบ•เปˆเบซเบ™เปˆเบงเบเบ„เบงเบฒเบกเบˆเปเบฒเบ–เบทเบเบ™เปเบฒเปƒเบŠเป‰เปเบฅเบฐเบšเปเปˆเปเบกเปˆเบ™เปเบœเปˆเบ™, เบซเบผเบฑเบ‡เบˆเบฒเบเบ™เบฑเป‰เบ™เบเบฒเบ™เบชเบญเบšเบ–เบฒเบกเบˆเบฐเป„เบงเบ‚เบถเป‰เบ™เบซเบผเบฒเบ. เปƒเบ™เป€เบงเบฅเบฒเบ”เบฝเบงเบเบฑเบ™, เบšเบฒเบ‡เบชเปˆเบงเบ™เบ‚เบญเบ‡เบเบฒเบ™เป‚เบซเบผเบ”เบเบฑเบ‡เบ–เบทเบเป‚เบเบเบเป‰เบฒเบเบญเบญเบเบˆเบฒเบ HDD.

เปเบ•เปˆเบ—เปˆเบฒเบ™เบˆเปเบฒเป€เบ›เบฑเบ™เบ•เป‰เบญเบ‡เป€เบ‚เบปเป‰เบฒเปƒเบˆเบงเปˆเบฒเบเบฒเบ™เบˆเบฑเบ”เบชเบฑเบ™เบ„เบงเบฒเบกเบŠเบปเบ‡เบˆเปเบฒเบซเบผเบฒเบเบˆเบฐเบšเปเปˆเป€เบฎเบฑเบ”เบงเบฝเบเบขเบนเปˆเบชเบฐเป€เบซเบกเบต - เบกเบฑเบ™เบšเปเปˆเบžเบฝเบ‡เบžเปเบชเปเบฒเบฅเบฑเบšเบ—เบธเบเบ„เบปเบ™.

#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 -- ั‡ะธั‚ะฐะปะธ ะผะฐะปะพ, ะฝะพ ัะปะธัˆะบะพะผ ะดะพะปะณะพ

เบ‚เปเป‰เบชเบฐเป€เบซเบ™เบตเปเบ™เบฐ

เปƒเบŠเป‰เบžเบฒเบเบ™เบญเบ เบฅเบฐโ€‹เบšเบปเบšโ€‹เบ•เบดเบ”โ€‹เบ•เบฒเบกโ€‹เบเบงเบ”โ€‹เบเบฒโ€‹ เป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบชเปเบฒเบฅเบฑเบšเบเบฒเบ™เบชเบฐเบเบฑเบ”เบซเบผเบทเบเบฒเบ™เบšเปเบฅเบดเป‚เบžเบเบŠเบฑเบšเบžเบฐเบเบฒเบเบญเบ™เบ—เบตเปˆเบœเบดเบ”เบ›เบปเบเบเบฐเบ•เบด. เบžเบงเบเป€เบฎเบปเบฒเป„เบ”เป‰เป€เบงเบปเป‰เบฒเบเปˆเบฝเบงเบเบฑเบšเบชเบฐเบšเบฑเบšเบ‚เบญเบ‡เบžเบงเบเป€เบฎเบปเบฒเปƒเบ™เบเบฒเบ™เบˆเบฑเบ”เบ•เบฑเป‰เบ‡เบ‚เบฐเบšเบงเบ™เบเบฒเบ™เบ™เบตเป‰เบชเปเบฒเบฅเบฑเบšเป€เบ„เบทเปˆเบญเบ‡เปเบกเปˆเบ‚เปˆเบฒเบเบซเบผเบฒเบเบฎเป‰เบญเบเบ„เบปเบ™. เบ—เบตเปˆเบ™เบตเป‰ ะธ เบ—เบตเปˆเบ™เบตเป‰.

เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries
เบชเบนเบ”เบชเปเบฒเบฅเบฑเบš Sick SQL Queries

เปเบซเบผเปˆเบ‡เบ‚เปเป‰เบกเบนเบ™: www.habr.com

เป€เบžเบตเปˆเบกเบ„เบงเบฒเบกเบ„เบดเบ”เป€เบซเบฑเบ™