αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ

αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“αžαŸ‚αž˜αž»αž“ αž™αžΎαž„β€‹αž”αžΆαž“β€‹αž”αŸ’αžšαž€αžΆαžŸ αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru - αžŸαžΆαž’αžΆαžšαžŽαŸˆ αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž‰αŸ‚αž€ αž“αž·αž„αž˜αžΎαž›αžƒαžΎαž‰αž•αŸ‚αž“αž€αžΆαžšαžŸαŸ†αžŽαž½αžš αž‘αŸ… PostgreSQL αŸ”

αž’αŸ’αž“αž€αž”αžΆαž“αž”αŸ’αžšαžΎαžœαžΆαž…αŸ’αžšαžΎαž“αž‡αžΆαž„ 6000 αžŠαž„αž αžΎαž™ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž˜αž»αžαž„αžΆαžšαž„αžΆαž™αžŸαŸ’αžšαž½αž›αž˜αž½αž™αžŠαŸ‚αž›αž”αŸ’αžšαž αŸ‚αž›αž‡αžΆαž˜αž·αž“αž˜αžΆαž“αž“αžšαžŽαžΆαž€αžαŸ‹αžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž“αŸ„αŸ‡αž‚αžΊ αžαž˜αŸ’αžšαž»αž™αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αžŠαŸ‚αž›αž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡αŸ–

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ

αžŸαŸ’αžαžΆαž”αŸ‹αž–αž½αž€αž‚αŸ αž αžΎαž™αžŸαŸ†αžŽαžΎαžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αž“αžΉαž„ "αž€αŸ’αž›αžΆαž™αž‡αžΆαžšαž›αžΌαž“ αž“αž·αž„αžŸαŸ’αž„αž”αŸ‹αžŸαŸ’αž„αžΆαžαŸ‹"αŸ” πŸ™‚

αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž’αŸ’αž„αž“αŸ‹αž’αŸ’αž„αžš αžŸαŸ’αžαžΆαž“αž—αžΆαž–αž‡αžΆαž…αŸ’αžšαžΎαž“αžŠαŸ‚αž›αž’αŸ’αžœαžΎαž±αŸ’αž™αžŸαŸ†αžŽαžΎαž™αžΊαžαž™αŸ‰αžΆαžœ αž“αž·αž„αžŸαŸ’αžšαŸαž€αžƒαŸ’αž›αžΆαž“αž’αž“αž’αžΆαž“ αž˜αžΆαž“αž›αž€αŸ’αžαžŽαŸˆαž’αž˜αŸ’αž˜αžαžΆ αž αžΎαž™αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αž‘αž½αž›αžŸαŸ’αž‚αžΆαž›αŸ‹αžŠαŸ„αž™αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’ αž“αž·αž„αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸƒαž•αŸ‚αž“αž€αžΆαžš.

αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž“αŸαŸ‡ αž’αŸ’αž“αž€αž’αž—αž·αžœαžŒαŸ’αžαž“αŸαž˜αŸ’αž“αžΆαž€αŸ‹αŸ—αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αžŸαŸ’αžœαŸ‚αž„αžšαž€αž‡αž˜αŸ’αžšαžΎαžŸαž”αž„αŸ’αž€αžΎαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αž‘αŸ αžŠαŸ„αž™αž–αžΉαž„αž•αŸ’αž’αŸ‚αž€αžαŸ‚αž›αžΎαž”αž‘αž–αž·αžŸαŸ„αž’αž“αŸαžšαž”αžŸαŸ‹αž‚αžΆαžαŸ‹ - αž™αžΎαž„αž’αžΆαž…αž”αŸ’αžšαžΆαž”αŸ‹αž‚αžΆαžαŸ‹αž–αžΈαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž€αŸ†αž–αž»αž„αž€αžΎαžαž‘αžΎαž„αž“αŸ…αž‘αžΈαž“αŸαŸ‡ αž’αŸ’αžœαžΈαžŠαŸ‚αž›αž’αžΆαž…αž‡αžΆαž αŸαžαž»αž•αž› αž“αž·αž„ αžšαž”αŸ€αž”β€‹αžšαž€β€‹αžŠαŸ†αžŽαŸ„αŸ‡αžŸαŸ’αžšαžΆαž™. αž“αŸ„αŸ‡αž αžΎαž™αž‡αžΆαž’αŸ’αžœαžΈαžŠαŸ‚αž›αž™αžΎαž„αž”αžΆαž“αž’αŸ’αžœαžΎαŸ”

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ

αžŸαžΌαž˜αž–αž·αž“αž·αžαŸ’αž™αž˜αžΎαž›αž±αŸ’αž™αž€αžΆαž“αŸ‹αžαŸ‚αž…αŸ’αž”αžΆαžŸαŸ‹αž’αŸ†αž–αžΈαž€αžšαžŽαžΈαž‘αžΆαŸ†αž„αž“αŸαŸ‡ - αžšαž”αŸ€αž”αžŠαŸ‚αž›αž–αž½αž€αžœαžΆαžαŸ’αžšαžΌαžœαž”αžΆαž“αž€αŸ†αžŽαžαŸ‹ αž“αž·αž„αž’αž“αž»αžŸαžΆαžŸαž“αŸαž’αŸ’αžœαžΈαžαŸ’αž›αŸ‡αžŠαŸ‚αž›αž–αž½αž€αž‚αŸαž“αžΆαŸ†αž‘αŸ…αžšαž€αŸ”

αžŠαžΎαž˜αŸ’αž”αžΈαž‡αŸ’αžšαž˜αž»αž‡αžαŸ’αž›αž½αž“αž’αŸ’αž“αž€αž±αŸ’αž™αž€αžΆαž“αŸ‹αžαŸ‚αž”αŸ’αžšαžŸαžΎαžšαž‘αžΎαž„αž“αŸ…αž€αŸ’αž“αž»αž„αž”αŸ’αžšαž’αžΆαž“αž”αž‘αžŠαŸ†αž”αžΌαž„αž’αŸ’αž“αž€αž’αžΆαž…αžŸαŸ’αžαžΆαž”αŸ‹αž”αŸ’αž›αž»αž€αžŠαŸ‚αž›αžαŸ’αžšαžΌαžœαž‚αŸ’αž“αžΆαž–αžΈ αžšαž”αžΆαž™αž€αžΆαžšαžŽαŸαžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αž“αŸ… PGConf.Russia 2020αž αžΎαž™αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž”αž“αŸ’αžαž‘αŸ…αž€αžΆαžšαžœαž·αž—αžΆαž‚αž›αž˜αŸ’αž’αž·αžαž“αŸƒαž§αž‘αžΆαž αžšαžŽαŸαž“αžΈαž˜αž½αž™αŸ—αŸ–

# 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;

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž’αŸ’αž“αž€αž’αžΆαž…αž€αžαŸ‹αžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αž—αŸ’αž›αžΆαž˜αŸ—αžαžΆαž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž…αŸ’αžšαžΎαž“αž‡αžΆαž„ 100 αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαž€αž…αŸαž‰αž–αžΈαž›αž·αž”αž·αž€αŸ’αžšαž˜ αžŠαŸ‚αž›αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αžαŸ’αžšαžΌαžœαž”αžΆαž“αžαž˜αŸ’αžšαŸ€αž”αž‘αžΆαŸ†αž„αž’αžŸαŸ‹ αž αžΎαž™αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž“αŸ…αžŸαž›αŸ‹αžαŸ‚αž˜αž½αž™αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡αŸ”

αž€αžΆαžšαž€αŸ‚αžαž˜αŸ’αžšαžΌαžœαŸ–

DROP INDEX tbl_fk_cli_idx;
CREATE INDEX ON tbl(fk_cli, pk DESC); -- Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ ΠΊΠ»ΡŽΡ‡ сортировки

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αžŸαžΌαž˜αŸ’αž”αžΈαžαŸ‚αž“αŸ…αž›αžΎαž‚αŸ†αžšαžΌαžŠαžΎαž˜αž”αŸ‚αž”αž“αŸαŸ‡ - αž›αžΏαž“αž‡αžΆαž„ 8.5 αžŠαž„ αž“αž·αž„αž’αžΆαž“αžαž·αž…αž‡αžΆαž„ 33 αžŠαž„. "αž€αžΆαžšαž–αž·αž" αž€αžΆαž“αŸ‹αžαŸ‚αž…αŸ’αžšαžΎαž“αžŠαŸ‚αž›αž’αŸ’αž“αž€αž˜αžΆαž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαž˜αŸ’αž›αŸƒαž“αžΈαž˜αž½αž™αŸ— αž₯αž‘αŸ’αž’αž·αž–αž›αž€αžΆαž“αŸ‹αžαŸ‚αž…αŸ’αž”αžΆαžŸαŸ‹ fk.

αžαŸ’αž‰αž»αŸ†αž€αžαŸ‹αžŸαž˜αŸ’αž‚αžΆαž›αŸ‹αžαžΆαžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸαž”αŸ‚αž”αž“αŸαŸ‡αž“αžΉαž„αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‡αžΆ "αž”αž»αž–αŸ’αžœαž”αž‘" αžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸαž˜αž·αž“αž’αžΆαž€αŸ’αžšαž€αŸ‹αž‡αžΆαž„αž–αžΈαž˜αž»αž“αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžšαž•αŸ’αžŸαŸαž„αž‘αŸ€αžαž‡αžΆαž˜αž½αž™ fkαžŠαŸ‚αž›αž‡αžΆαž€αž“αŸ’αž›αŸ‚αž„αžŠαŸ‚αž›αžαž˜αŸ’αžšαŸ€αž”αžαžΆαž˜ pk αžœαžΆαž˜αž·αž“αž˜αžΆαž“ αž“αž·αž„αž˜αž·αž“αž˜αžΆαž“ (αž’αŸ’αž“αž€αž’αžΆαž…αž’αžΆαž“αž”αž“αŸ’αžαŸ‚αž˜αž’αŸ†αž–αžΈαžšαžΏαž„αž“αŸαŸ‡ αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ†αž’αŸ†αž–αžΈαž€αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αž›αž·αž”αž·αž€αŸ’αžšαž˜αžŠαŸ‚αž›αž˜αž·αž“αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–) αžšαž½αž˜αž‘αžΆαŸ†αž„αžœαžΆαž“αžΉαž„αž•αŸ’αžαž›αŸ‹αž’αž˜αŸ’αž˜αžαžΆαŸ” αž€αžΆαžšαž‚αžΆαŸ†αž‘αŸ’αžšαž‚αž“αŸ’αž›αžΉαŸ‡αž”αžšαž‘αŸαžŸαž…αŸ’αž”αžΆαžŸαŸ‹αž›αžΆαžŸαŸ‹ αž“αŸ…αž›αžΎαžœαžΆαž›αž“αŸαŸ‡αŸ”

# 2: αž…αŸ†αž“αž»αž…αž”αŸ’αžšαžŸαž–αŸ’αžœαžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸ (BitmapAnd)

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αž”αž„αŸ’αž αžΆαž‰αž€αž·αž…αŸ’αž…αž–αŸ’αžšαž˜αž–αŸ’αžšαŸ€αž„αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž’αžαž·αžαž·αž‡αž“ "LLC Kolokolchik" αžŠαŸ‚αž›αž”αžΆαž“αž”αž‰αŸ’αž…αž”αŸ‹αž€αŸ’αž“αž»αž„αž“αžΆαž˜ "NAO Buttercup" αŸ”

αžšαž”αŸ€αž”αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽ

-> 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); -- ΠΎΡ‚Π±ΠΎΡ€ ΠΏΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ ΠΏΠ°Ρ€Π΅

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž€αžΆαžšαž€αŸ‚αžαž˜αŸ’αžšαžΌαžœαŸ–

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

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž€αžΆαžšαž‘αžΌαž‘αžΆαžαŸ‹αž“αŸ…αž‘αžΈαž“αŸαŸ‡αž‚αžΊαžαžΌαž…αž‡αžΆαž„ αžŠαŸ„αž™αžŸαžΆαžš Bitmap Heap Scan αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αžŽαžΆαžŸαŸ‹αžŠαŸ„αž™αžαŸ’αž›αž½αž“αž―αž„αŸ” αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž™αŸ‰αžΆαž„αžŽαžΆαž€αŸαžŠαŸ„αž™ αž›αžΏαž“αž‡αžΆαž„ 7 αžŠαž„ αž“αž·αž„αž’αžΆαž“αžαž·αž…αž‡αžΆαž„ 2.5 αžŠαž„.

# 3: αž”αž‰αŸ’αž…αžΌαž›αžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸ (BitmapOr)

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αž”αž„αŸ’αž αžΆαž‰ "αž–αž½αž€αž™αžΎαž„" αžŠαŸ‚αž›αž…αžΆαžŸαŸ‹αž‡αžΆαž„αž‚αŸαž…αŸ†αž“αž½αž“ 20 αž“αžΆαž€αŸ‹αžŠαŸ†αž”αžΌαž„ αž¬αžŸαŸ†αžŽαžΎαžŠαŸ‚αž›αž˜αž·αž“αž‘αžΆαž“αŸ‹αž”αžΆαž“αž…αžΆαžαŸ‹αžαžΆαŸ†αž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžš αžŠαŸ„αž™αž˜αžΆαž“αž’αžΆαž‘αž·αž—αžΆαž–αžšαž”αžŸαŸ‹αž’αŸ’αž“αž€αŸ”

αžšαž”αŸ€αž”αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽ

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

αž’αž“αž»αžŸαžΆαžŸαž“αŸ

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ αžŸαž αž—αžΆαž– [αž‘αžΆαŸ†αž„αž’αžŸαŸ‹] αžŠαžΎαž˜αŸ’αž”αžΈαž”αž‰αŸ’αž…αžΌαž›αž‚αŸ’αž“αžΆαž“αžΌαžœαžŸαŸ†αžŽαž½αžšαžšαž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ OR-blocks αž“αŸƒαž›αž€αŸ’αžαžαžŽαŸ’αžŒαž“αžΈαž˜αž½αž™αŸ—αŸ”

αž§αž‘αžΆαž αžšαžŽαŸ:

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;

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.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, большС и нС надо

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž™αžΎαž„αž”αžΆαž“αž‘αžΆαž‰αž™αž€αž”αŸ’αžšαž™αŸ„αž‡αž“αŸαž–αžΈαž€αžΆαžšαž–αž·αžαžŠαŸ‚αž›αžαžΆαž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαžŠαŸ‚αž›αž‘αžΆαž˜αž‘αžΆαžšαž‘αžΆαŸ†αž„ 20 αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‘αž‘αž½αž›αž—αŸ’αž›αžΆαž˜αŸ—αž“αŸ…αž€αŸ’αž“αž»αž„αž”αŸ’αž›αž»αž€αž‘αžΈαž˜αž½αž™ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž‘αžΈαž–αžΈαžšαž‡αžΆαž˜αž½αž™αž“αžΉαž„ Bitmap Heap Scan αžŠαŸ‚αž›αž˜αžΆαž“αžαž˜αŸ’αž›αŸƒαžαŸ’αž›αŸƒαž‡αžΆαž„ αž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αžŸαžΌαž˜αŸ’αž”αžΈαžαŸ‚ - αž“αŸ…αž‘αžΈαž”αž‰αŸ’αž…αž”αŸ‹ αž›αžΏαž“αž‡αžΆαž„ 22 αžŠαž„ αž’αžΆαž“αžαž·αž…αž‡αžΆαž„ 44 αžŠαž„!

αžšαžΏαž„αž›αž˜αŸ’αž’αž·αžαž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αžαž’αŸ†αž–αžΈαžœαž·αž’αžΈαžŸαžΆαžŸαŸ’αžαŸ’αžšαž”αž„αŸ’αž€αžΎαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž“αŸαŸ‡αŸ” αžŠαŸ„αž™αž”αŸ’αžšαžΎαž§αž‘αžΆαž αžšαžŽαŸαž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹ αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž’αžΆαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘ PostgreSQL AntipatternsαŸ– αž€αžΆαžšαž…αžΌαž›αžšαž½αž˜ αž“αž·αž„ ORs αžŠαŸ‚αž›αž”αž„αŸ’αž€αž‚αŸ’αžšαŸ„αŸ‡αžαŸ’αž“αžΆαž€αŸ‹ ΠΈ PostgreSQL AntipatternsαŸ– αžšαžΏαž„αžšαŸ‰αžΆαžœαž“αŸƒαž€αžΆαžšαž…αž˜αŸ’αžšαžΆαž‰αŸ‹αž‘αžΎαž„αžœαž·αž‰αž“αŸƒαž€αžΆαžšαžŸαŸ’αžœαŸ‚αž„αžšαž€αžαžΆαž˜αžˆαŸ’αž˜αŸ„αŸ‡ ឬ β€œαž€αžΆαžšαž”αž„αŸ’αž€αžΎαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž‘αŸ…αžœαž·αž‰αž‘αŸ…αž˜αž€β€.

αž€αŸ†αžŽαŸ‚αž‘αžΌαž‘αŸ… αž€αžΆαžšαž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαžαžΆαž˜αž›αŸ†αžŠαžΆαž”αŸ‹αžŠαŸ„αž™αž•αŸ’αž’αŸ‚αž€αž›αžΎαž‚αŸ’αžšαžΆαž”αŸ‹αž…αž»αž…αž‡αžΆαž…αŸ’αžšαžΎαž“αŸ” (αž“αž·αž„αž˜αž·αž“αžαŸ’αžšαžΉαž˜αžαŸ‚αž‚αžΌ const/NULL) αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž—αžΆαž€αŸ’αžŸαžΆαž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘ SQL HowTo: សរសេរ while-loop αžŠαŸ„αž™αž•αŸ’αž‘αžΆαž›αŸ‹αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαŸ†αžŽαž½αžš ឬ "Elementary three-way".

#αŸ€αŸ– αž™αžΎαž„αž’αžΆαž“αžšαžΏαž„αžŠαŸ‚αž›αž˜αž·αž“αž…αžΆαŸ†αž”αžΆαž…αŸ‹αž…αŸ’αžšαžΎαž“αŸ”

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αžαžΆαž˜αž€αŸ’αž”αž½αž“αžœαžΆαž€αžΎαžαž‘αžΎαž„αž“αŸ…αž–αŸαž›αž’αŸ’αž“αž€αž…αž„αŸ‹ "αž—αŸ’αž‡αžΆαž”αŸ‹αžαž˜αŸ’αžšαž„αž•αŸ’αžŸαŸαž„αž‘αŸ€αž" αž‘αŸ…αž“αžΉαž„αžŸαŸ†αžŽαžΎαžŠαŸ‚αž›αž˜αžΆαž“αžŸαŸ’αžšαžΆαž”αŸ‹αŸ”

"αž αžΎαž™αž’αŸ’αž“αž€αž˜αž·αž“αž˜αžΆαž“αžŠαžΌαž…αž‚αŸ’αž“αžΆαž‘αŸ αž”αŸ‰αž»αž“αŸ’αžαŸ‚ αž‡αžΆαž˜αž½αž™αž“αžΉαž„αž”αŸŠαžΌαžαž»αž„αž‚αž»αž‡αžαŸ’αž™αž„? αžαŸ’αžŸαŸ‚αž—αžΆαž–αž™αž“αŸ’αž "αžŠαŸƒαž–αŸαž‡αŸ’αžš"

αž§αž‘αžΆαž αžšαžŽαŸ αž€αžΆαžšαž€αŸ‚αž”αŸ’αžšαŸ‚αž€αž·αž…αŸ’αž…αž€αžΆαžšαžαžΆαž„αž›αžΎ αž”αž„αŸ’αž αžΆαž‰αžŸαŸ†αžŽαžΎ "αžŸαŸ†αžαžΆαž“αŸ‹" αž…αžΆαžŸαŸ‹αž”αŸ†αž•αž»αžαž…αŸ†αž“αž½αž“ 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;

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž€αžΆαžšαž€αŸ‚αžαž˜αŸ’αžšαžΌαžœαŸ–

CREATE INDEX ON tbl(pk)
  WHERE critical; -- Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ "статичноС" условиС Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αžŠαžΌαž…αžŠαŸ‚αž›αž’αŸ’αž“αž€αž”αžΆαž“αžƒαžΎαž‰ αž€αžΆαžšαžαŸ’αžšαž„αž”αžΆαž“αž”αžΆαžαŸ‹αž‘αžΆαŸ†αž„αžŸαŸ’αžšαž»αž„αž–αžΈαž•αŸ‚αž“αž€αžΆαžš αž αžΎαž™αžŸαŸ†αžŽαžΎαž”αžΆαž“αž€αŸ’αž›αžΆαž™αž‘αŸ…αž‡αžΆ αž›αžΏαž“αž‡αžΆαž„ 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 [αž–αŸαž‰] αž¬αž‘αž‘αž½αž›αž”αžΆαž“αž€αžΆαžšαž”αžŽαŸ’αžαž»αŸ‡αž”αžŽαŸ’αžαžΆαž›αž±αŸ’αž™αž”αžΆαž“αž‰αžΉαž€αž‰αžΆαž”αŸ‹αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹ αžŸαŸ’αžœαŸαž™αž”αŸ’αžšαžœαžαŸ’αžαž· αžŠαŸ„αž™αž€αžΆαžšαž›αŸƒαžαž˜αŸ’αžšαžΌαžœαž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžšαžšαž”αžŸαŸ‹αžœαžΆ αžšαž½αž˜αž‘αžΆαŸ†αž„ αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžαžΆαžšαžΆαž„αž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹.

αž€αŸ’αž“αž»αž„αž€αžšαžŽαžΈαž—αžΆαž‚αž…αŸ’αžšαžΎαž“ αž”αž‰αŸ’αž αžΆαž”αŸ‚αž”αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž€αž‘αžΎαž„αžŠαŸ„αž™αžŸαž˜αžΆαžŸαž—αžΆαž–αžŸαŸ†αžŽαž½αžšαž˜αž·αž“αž›αŸ’αž’ αž“αŸ…αž–αŸαž›αž αŸ…αž…αŸαž‰αž–αžΈαžαž€αŸ’αž€αžœαž·αž‡αŸ’αž‡αžΆαž’αžΆαž‡αžΈαžœαž€αž˜αŸ’αž˜αžŠαžΌαž…αž’αŸ’αžœαžΈαžŠαŸ‚αž›αž”αžΆαž“αž–αž·αž—αžΆαž€αŸ’αžŸαžΆ 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;

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž’αŸ’αžœαžΈαž‚αŸ’αžšαž”αŸ‹αž™αŸ‰αžΆαž„αž αžΆαž€αŸ‹αžŠαžΌαž…αž‡αžΆαž›αŸ’αž’ αž‘αŸ„αŸ‡αž”αžΈαž‡αžΆαž™αŸ„αž„αž‘αŸ…αžαžΆαž˜αžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸαž€αŸαžŠαŸ„αž™ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αžœαžΆαž‚αž½αžšαž±αŸ’αž™αžŸαž„αŸ’αžŸαŸαž™ - αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž“αžΈαž˜αž½αž™αŸ—αž“αŸƒ 20 αžŠαŸ‚αž›αž”αžΆαž“αž’αžΆαž“ αž™αžΎαž„αžαŸ’αžšαžΌαžœαžŠαž€αž‘αž·αž“αŸ’αž“αž“αŸαž™ 4 αž‘αŸ†αž–αŸαžš 32KB αž€αŸ’αž“αž»αž„αž˜αž½αž™αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆ - αžαžΎαžœαžΆαž˜αž·αž“αžŠαž·αžαž‘αŸ? αž“αž·αž„αžˆαŸ’αž˜αŸ„αŸ‡αžŸαž“αŸ’αž‘αžŸαŸ’αžŸαž“αŸ tbl_fk_org_fk_cli_idx αž”αŸ†αž•αž»αžŸαž‚αŸ†αž“αž·αžαŸ”

αž€αžΆαžšαž€αŸ‚αžαž˜αŸ’αžšαžΌαžœαŸ–

CREATE INDEX ON tbl(fk_cli);

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž—αŸ’αž›αžΆαž˜αŸ— - αž›αžΏαž“αž‡αžΆαž„αž˜αž»αž“ 10 αžŠαž„ αž“αž·αž„αž’αžΆαž“αžαž·αž…αž‡αžΆαž„ 4 αžŠαž„!

αž§αž‘αžΆαž αžšαžŽαŸαž•αŸ’αžŸαŸαž„αž‘αŸ€αžαž“αŸƒαžŸαŸ’αžαžΆαž“αž—αžΆαž–αž“αŸƒαž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž›αž·αž”αž·αž€αŸ’αžšαž˜αžŠαŸ‚αž›αž˜αž·αž“αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αŸαž˜αžΎαž›αžƒαžΎαž‰αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘ DBA: αžŸαŸ’αžœαŸ‚αž„αžšαž€αž›αž·αž”αž·αž€αŸ’αžšαž˜αžŠαŸ‚αž›αž‚αŸ’αž˜αžΆαž“αž”αŸ’αžšαž™αŸ„αž‡αž“αŸ.

αž›αŸαž αŸ§αŸ– CTE Γ— CTE

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αžαžΆαž˜αž€αžΆαžšαžŸαŸ’αž“αžΎαžŸαž»αŸ† αž‘αž‘αž½αž›αž”αžΆαž“αž–αž·αž“αŸ’αž‘αž» "αžαŸ’αž›αžΆαž‰αŸ‹" CTE αž–αžΈαžαž»αž•αŸ’αžŸαŸαž„αž‚αŸ’αž“αžΆ αž αžΎαž™αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αžŸαž˜αŸ’αžšαŸαž…αž…αž·αžαŸ’αžαž’αŸ’αžœαžΎαžœαžΆαžšαžœαžΆαž„αž–αž½αž€αž‚αŸαŸ” JOIN.

αž€αžšαžŽαžΈαž“αŸαŸ‡αž‚αžΊαž–αžΆαž€αŸ‹αž–αŸαž“αŸ’αž’αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αŸ†αžŽαŸ‚αžαžΆαž„αž€αŸ’αžšαŸ„αž˜ v12 αž¬αžŸαŸ†αžŽαžΎαž‡αžΆαž˜αž½αž™ WITH MATERIALIZED.

αžšαž”αŸ€αž”αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽ

-> CTE Scan
   && loops > 10
   && loops Γ— (rows + RRbF) > 10000
      -- слишком большоС Π΄Π΅ΠΊΠ°Ρ€Ρ‚ΠΎΠ²ΠΎ ΠΏΡ€ΠΎΠΈΠ·Π²Π΅Π΄Π΅Π½ΠΈΠ΅ CTE

αž’αž“αž»αžŸαžΆαžŸαž“αŸ

αžœαž·αž—αžΆαž‚αžŠαŸ„αž™αž”αŸ’αžšαž»αž„αž”αŸ’αžšαž™αŸαžαŸ’αž“αž“αžΌαžœαžŸαŸ†αžŽαžΎ - αž“αž·αž„ តើ CTEs αžαŸ’αžšαžΌαžœαž€αžΆαžšαž“αŸ…αž‘αžΈαž“αŸαŸ‡αž‘αŸ?? αž”αžΎαž”αžΆαž‘ αž’αž‰αŸ’αž…αžΉαž„ αž’αž“αž»αžœαžαŸ’αž "αžœαž…αž“αžΆαž“αž»αž€αŸ’αžšαž˜" αž“αŸ…αž€αŸ’αž“αž»αž„ hstore/json αž“αŸαŸ‡αž”αžΎαž™αŸ„αž„αžαžΆαž˜αž‚αŸ†αžšαžΌαžŠαŸ‚αž›αž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαž“αŸ…αž€αŸ’αž“αž»αž„ PostgreSQL AntipatternsαŸ– αžαŸ„αŸ‡αž…αž»αž… JOIN αž’αŸ’αž„αž“αŸ‹αŸ—αž‡αžΆαž˜αž½αž™αžœαž…αž“αžΆαž“αž»αž€αŸ’αžšαž˜.

αž›αŸαž αŸ¨αŸ– αž”αŸ’αžαžΌαžšαž‘αŸ…αžŒαžΈαžŸ (αž–αž»αž˜αŸ’αž–αžŸαžšαžŸαŸαžš)

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαžαŸ‚αž˜αž½αž™αžŠαž„ (αž€αžΆαžšαžαž˜αŸ’αžšαŸ€αž” αž¬αž€αžΆαžšαž’αŸ’αžœαžΎαž”αŸ’αž›αŸ‚αž€αž–αžΈαž‚αŸ) αž“αŸƒαž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž˜αž½αž™αž…αŸ†αž“αž½αž“αž’αŸ†αž˜αž·αž“αžŸαž˜αž“αžΉαž„αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ†αžŠαŸ‚αž›αž”αžΆαž“αž”αž˜αŸ’αžšαž»αž„αž‘αž»αž€αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž“αŸαŸ‡αž‘αŸαŸ”

αžšαž”αŸ€αž”αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽ

-> *
   && temp written > 0

αž’αž“αž»αžŸαžΆαžŸαž“αŸ

αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž”αžšαž·αž˜αžΆαžŽαž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ†αžŠαŸ‚αž›αž”αŸ’αžšαžΎαžŠαŸ„αž™αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαž˜αž·αž“αž›αžΎαžŸαž–αžΈαžαž˜αŸ’αž›αŸƒαžŠαŸ‚αž›αž”αžΆαž“αž”αž‰αŸ’αž‡αžΆαž€αŸ‹αž“αŸƒαž”αŸ‰αžΆαžšαŸ‰αžΆαž˜αŸ‰αŸ‚αžαŸ’αžš work_memαžœαžΆαž‚αžΊαž˜αžΆαž“αžαŸ†αž›αŸƒαž€αŸ‚αžαž˜αŸ’αžšαžΌαžœαžœαžΆαŸ” αž’αŸ’αž“αž€αž’αžΆαž…αž—αŸ’αž›αžΆαž˜αŸ—αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž€αŸ†αžŽαžαŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž˜αž“αž»αžŸαŸ’αžŸαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αž“αžΆ αž¬αž’αŸ’αž“αž€αž’αžΆαž…αž†αŸ’αž›αž„αž€αžΆαžαŸ‹αž”αžΆαž“αŸ” SET [LOCAL] αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαžΎ/αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαž‡αžΆαž€αŸ‹αž›αžΆαž€αŸ‹αŸ”

αž§αž‘αžΆαž αžšαžŽαŸ:

SHOW work_mem;
-- "16MB"

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

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αž€αžΆαžšαž€αŸ‚αžαž˜αŸ’αžšαžΌαžœαŸ–

SET work_mem = '128MB'; -- ΠΏΠ΅Ρ€Π΅Π΄ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ΠΌ запроса

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
[αžŸαžΌαž˜αž˜αžΎαž›αž–αž“αŸ’αž™αž›αŸ‹.tensor.ru]

αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž αŸαžαž»αž•αž›αž‡αžΆαž€αŸ‹αžŸαŸ’αžαŸ‚αž„ αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž”αŸ’αžšαžΎαžαŸ‚αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ†αž”αŸ‰αž»αžŽαŸ’αžŽαŸ„αŸ‡ αž αžΎαž™αž˜αž·αž“αž˜αŸ‚αž“αžαžΆαžŸαž‘αŸ αž“αŸ„αŸ‡αžŸαŸ†αžŽαž½αžšαž“αžΉαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž›αžΏαž“αž‡αžΆαž„αž˜αž»αž“αŸ” αž€αŸ’αž“αž»αž„αž–αŸαž›αž‡αžΆαž˜αž½αž™αž‚αŸ’αž“αžΆαž“αŸαŸ‡αž•αŸ’αž“αŸ‚αž€αž˜αž½αž™αž“αŸƒαž”αž“αŸ’αž‘αž»αž€αž–αžΈ HDD αž€αŸαžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαž€αž…αŸαž‰αž•αž„αžŠαŸ‚αžšαŸ”

αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž’αŸ’αž“αž€αžαŸ’αžšαžΌαžœαž™αž›αŸ‹αžαžΆ αž’αŸ’αž“αž€αž“αžΉαž„αž˜αž·αž“αž’αžΆαž…αž”αŸ‚αž„αž…αŸ‚αž€αž€αžΆαžšαž…αž„αž…αžΆαŸ†αž”αžΆαž“αž…αŸ’αžšαžΎαž“ αž“αž·αž„αž…αŸ’αžšαžΎαž“αž“αŸ„αŸ‡αž‘αŸ - αžœαžΆαž“αžΉαž„αž˜αž·αž“αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž˜αž“αž»αžŸαŸ’αžŸαž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αž“αžΆαž“αŸ„αŸ‡αž‘αŸαŸ”

αž›αŸαž αŸ©αŸ– αžŸαŸ’αžαž·αžαž·αž˜αž·αž“αž–αžΆαž€αŸ‹αž–αŸαž“αŸ’αž’

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αž–αž½αž€αž‚αŸαž”αžΆαž“αž…αžΆαž€αŸ‹αž…αŸ’αžšαžΎαž“αž…αžΌαž›αž‘αŸ…αž€αŸ’αž“αž»αž„αž˜αžΌαž›αžŠαŸ’αž‹αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αž€αŸ’αž“αž»αž„αž–αŸαž›αžαŸ‚αž˜αž½αž™ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž˜αž·αž“αž˜αžΆαž“αž–αŸαž›αžŠαžΎαž˜αŸ’αž”αžΈαž‡αŸ†αžšαž»αž‰αžœαžΆαž…αŸαž‰αž‘αŸαŸ” ANALYZE.

αžšαž”αŸ€αž”αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽ

-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
   && ratio >> 10

αž’αž“αž»αžŸαžΆαžŸαž“αŸ

αž’αž“αž»αžœαžαŸ’αžαžœαžΆαž…αŸαž‰ ANALYZE.

αžŸαŸ’αžαžΆαž“αž—αžΆαž–αž“αŸαŸ‡αžαŸ’αžšαžΌαžœαž”αžΆαž“αž–αž·αž–αžŽαŸŒαž“αžΆαž›αž˜αŸ’αž’αž·αžαž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αžαž“αŸ…αž€αŸ’αž“αž»αž„ PostgreSQL Antipatterns: αžŸαŸ’αžαž·αžαž·αž‚αžΊαž‡αžΆαž’αŸ’αžœαžΈαž‚αŸ’αžšαž”αŸ‹αž™αŸ‰αžΆαž„.

αž›αŸαž αŸ‘αŸ αŸ– "αž˜αžΆαž“αž’αŸ’αžœαžΈαž˜αž½αž™αžαž»αžŸαž”αŸ’αžšαž€αŸ’αžšαžαžΈ"

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž€αžΎαžαž‘αžΎαž„

αž˜αžΆαž“αž€αžΆαžšαžšαž„αŸ‹αž…αžΆαŸ†αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž…αžΆαž€αŸ‹αžŸαŸ„αžšαžŠαŸ‚αž›αž’αŸ’αžœαžΎαž‘αžΎαž„αžŠαŸ„αž™αžŸαŸ†αžŽαžΎαž”αŸ’αžšαž€αž½αžαž”αŸ’αžšαž‡αŸ‚αž„ αž¬αž˜αžΆαž“αž’αž“αž’αžΆαž“αž•αŸ’αž“αŸ‚αž€αžšαžΉαž„ CPU/hypervisor αž˜αž·αž“αž‚αŸ’αžšαž”αŸ‹αž‚αŸ’αžšαžΆαž“αŸ‹αŸ”

αžšαž”αŸ€αž”αž€αŸ†αžŽαžαŸ‹αž’αžαŸ’αžαžŸαž‰αŸ’αž‰αžΆαžŽ

-> *
   && (shared hit / 8K) + (shared read / 1K) < time / 1000
      -- RAM hit = 64MB/s, HDD read = 8MB/s
   && time > 100ms -- Ρ‡ΠΈΡ‚Π°Π»ΠΈ ΠΌΠ°Π»ΠΎ, Π½ΠΎ слишком Π΄ΠΎΠ»Π³ΠΎ

αž’αž“αž»αžŸαžΆαžŸαž“αŸ

αž”αŸ’αžšαžΎαžαžΆαž„αž€αŸ’αžšαŸ… αž”αŸ’αžšαž–αŸαž“αŸ’αž’αžαŸ’αžšαž½αžαž–αž·αž“αž·αžαŸ’αž™ αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž€αžΆαžšαž‘αž”αŸ‹αžŸαŸ’αž€αžΆαžαŸ‹ αž¬αž€αžΆαžšαž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹αž’αž“αž’αžΆαž“αž˜αž·αž“αž”αŸ’αžšαž€αŸ’αžšαžαžΈαŸ” αž™αžΎαž„αž”αžΆαž“αž“αž·αž™αžΆαž™αžšαž½αž…αž αžΎαž™αž’αŸ†αž–αžΈαž€αŸ†αžŽαŸ‚αžšαž”αžŸαŸ‹αž™αžΎαž„αž“αŸƒαž€αžΆαžšαžšαŸ€αž”αž…αŸ†αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž“αŸαŸ‡αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αž˜αŸ‰αžΆαžŸαŸŠαžΈαž“αž˜αŸαžšαžΆαž”αŸ‹αžšαž™ αž“αŸ…αž‘αžΈαž“αŸαŸ‡ ΠΈ αž“αŸ…αž‘αžΈαž“αŸαŸ‡.

αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ
αžšαžΌαž”αž˜αž“αŸ’αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž½αžš SQL ឈឺ

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹