توھان اڳ ۾ ئي ان کي 6000 کان وڌيڪ ڀيرا استعمال ڪيو آھي، پر ھڪڙي ھلندڙ خصوصيت جيڪا ٿي سگھي ٿي ڪنھن جو ڌيان نه ويو آھي ساخت جا اشارا، جيڪو ڪجهه هن طرح نظر اچي ٿو:
انهن کي ٻڌو، ۽ توهان جون درخواستون "هموار ۽ ريشمي ٿي ويندا." 🙂
پر سنجيدگي سان، ڪيتريون ئي حالتون جيڪي درخواست ڏين ٿيون سست ۽ وسيلن جي بکيو عام آهن ۽ پلان جي ڍانچي ۽ ڊيٽا کي سڃاڻي سگهجي ٿو.
انهي صورت ۾، هر فرد ڊولپر کي پنهنجي طور تي هڪ اصلاحي اختيار ڳولڻ جي ضرورت ناهي، صرف پنهنجي تجربي تي ڀروسو ڪندي - اسان کيس ٻڌائي سگهون ٿا ته هتي ڇا ٿي رهيو آهي، سبب ڇا ٿي سگهي ٿو، ۽ هڪ حل کي ڪيئن حاصل ڪجي. اهو ئي اسان ڪيو.
اچو ته انهن ڪيسن تي هڪ ويجهي نظر رکون - اهي ڪيئن بيان ڪيا ويا آهن ۽ ڪهڙيون سفارشون انهن جي اڳواڻي ڪن ٿا.
موضوع ۾ پنهنجو پاڻ کي بهتر ڪرڻ لاءِ، توهان پهرين ٻڌي سگهو ٿا لاڳاپيل بلاڪ تان منهنجي رپورٽ PGConf.Russia 2020 تي، ۽ صرف پوءِ هر مثال جي تفصيلي تجزيو ڏانهن وڃو:
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;
-> 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); -- отбор по конкретной паре
پهرين 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;
(
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 سان، ان تي عمل نه ڪيو ويو - آخر ۾ 22x تيز، 44x گھٽ پڙھڻ!
ضابطي جي طور تي، اهو پيدا ٿئي ٿو جڏهن توهان چاهيو ٿا "ٻيو فلٽر ڳنڍيو" اڳ ۾ ئي موجود درخواست تي.
”۽ توهان وٽ ساڳيو ناهي، پر ماء جي موتي بٽڻ سان؟ » فلم "هيرن جي بازو"
مثال طور، مٿي ڏنل ڪم کي تبديل ڪندي، ڏيکاريو پهرين 20 پراڻين ”نازڪ“ درخواستن کي پروسيسنگ لاءِ، انهن جي مقصد کان سواءِ.
سڃاڻپ ڪيئن ڪجي
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& 5 × rows < RRbF -- отфильтровано >80% прочитанного
&& loops × RRbF > 100 -- и при этом больше 100 записей суммарно
سفارشون
ٺاهيو [وڌيڪ] خاص انڊيڪس WHERE شرط سان يا انڊيڪس ۾ اضافي شعبا شامل ڪريو.
جيڪڏهن فلٽر شرط توهان جي مقصدن لاء "جامد" آهي - اهو آهي وڌائڻ جو مطلب نه آهي مستقبل ۾ قدرن جي فهرست - اھو بھتر آھي استعمال ڪرڻ لاءِ WHERE انڊيڪس. مختلف boolean/enum Status هن درجي ۾ چڱيءَ طرح فٽ ٿين ٿا.
جيڪڏهن فلٽرنگ جي حالت مختلف معنائون وٺي سگھي ٿو، پوءِ اھو بھتر آھي ته انڊيڪس کي انھن شعبن سان وڌايو - جيئن Bitmap ۽ مٿي جي صورتحال ۾.
مثال طور
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;
توهان جي پنهنجي ٽاسڪ پروسيسنگ قطار ٺاهڻ لاءِ مختلف ڪوششون، جڏهن ٽيبل تي رڪارڊن جي وڏي تعداد ۾ تازه ڪاريون/ ڊليٽ ڪرڻ سان ”مئل“ رڪارڊ جي وڏي تعداد جي صورتحال پيدا ٿئي ٿي.
سڃاڻپ ڪيئن ڪجي
-> Seq Scan | Bitmap Heap Scan | Index [Only] Scan [Backward]
&& loops × (rows + RRbF) < (shared hit + shared read) × 8
-- прочитано больше 1KB на каждую запись
&& shared hit + shared read > 64
سفارشون
دستي طور تي باقاعده عمل ڪريو ويڪيوم [مڪمل] يا مناسب طور تي بار بار تربيت حاصل ڪريو خودڪار ويڪيوم ان جي پيٽرولن کي ٺيڪ ڪرڻ سان، بشمول هڪ مخصوص ٽيبل لاء.
اهو لڳي ٿو ته اسان ٿورو پڙهيو آهي، ۽ هر شيء کي ترتيب ڏني وئي هئي، ۽ اسان ڪنهن کي به وڌيڪ فلٽر نه ڪيو آهي - پر تڏهن به اسان گهڻو ڪري وڌيڪ صفحا پڙهي سگهون ٿا جيڪي اسان چاهيون ٿا.
سڃاڻپ ڪيئن ڪجي
-> 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 سوچڻ وارو.
ھڪڙي وقت جي پروسيسنگ (ترتيب يا منفرد ڪرڻ) جي رڪارڊ جي وڏي تعداد ۾ ھن لاء مختص ڪيل ياداشت ۾ مناسب نه آھي.
سڃاڻپ ڪيئن ڪجي
-> *
&& temp written > 0
سفارشون
جيڪڏهن آپريشن پاران استعمال ڪيل ميموري جي مقدار کي پيٽرولر جي مخصوص قيمت کان وڌيڪ نه آهي ڪم_ميم، ان کي درست ڪرڻ جي قابل آهي. توهان فوري طور تي هر ڪنهن لاء ترتيب ۾ ڪري سگهو ٿا، يا توهان ذريعي ڪري سگهو ٿا SET [LOCAL] مخصوص درخواست / ٽرانزيڪشن لاءِ.
مثال طور
SHOW work_mem;
-- "16MB"
SELECT
random()
FROM
generate_series(1, 1000000)
ORDER BY
1;
مقابلي واري درخواست پاران لاڳو ٿيل تالا جو انتظار هو، يا اتي ڪافي نه هئا CPU/hypervisor هارڊويئر وسيلا.
سڃاڻپ ڪيئن ڪجي
-> *
&& (shared hit / 8K) + (shared read / 1K) < time / 1000
-- RAM hit = 64MB/s, HDD read = 8MB/s
&& time > 100ms -- читали мало, но слишком долго
سفارشون
خارجي استعمال ڪريو نگراني نظام سرور بلاڪ ڪرڻ يا غير معمولي وسيلن جي استعمال لاء. اسان اڳ ۾ ئي ڳالهائي چڪا آهيون اسان جي ورزن کي ترتيب ڏيڻ جي هن پروسيس کي سوين سرورز لاءِ هتي и هتي.