SELECT
count(*)
FROM
acc_{account_id}.urls as recordings_urls,
acc_{account_id}.recording_data as recording_data,
acc_{account_id}.sessions as sessions
WHERE
recording_data.usp_id = sessions.usp_id
AND sessions.referrer_id = recordings_urls.id
AND ( urls && array(select id from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com/jobs%')::text[] )
AND r_time > to_timestamp(1542585600)
AND r_time < to_timestamp(1545177599)
AND recording_data.duration >=5
AND recording_data.num_of_pages > 0 ;
۽ هتي وقت آهن:
منصوبه بندي جو وقت: 1.480 ايم ايس ايگزيڪيوشن جو وقت: 1431924.650 ايم ايس
پڇا ڳاڇا ڪئي وئي 150 هزار قطارون. سوال جي منصوبه بندي ڪندڙ ڪجهه دلچسپ تفصيل ڏيکاريا، پر ڪابه واضح رڪاوٽ نه.
اچو ته درخواست جو وڌيڪ مطالعو ڪريون. جيئن توهان ڏسي سگهو ٿا، هو ڪندو آهي JOIN ٽي ٽيبل:
سيشن: سيشن جي معلومات ڏيکارڻ لاءِ: برائوزر، يوزر ايجنٽ، ملڪ، وغيره.
رڪارڊنگ_ڊيٽا: رڪارڊ ٿيل URLs، صفحا، دورن جو عرصو
يوزائين: تمام وڏا URLs نقل ڪرڻ کان بچڻ لاءِ، اسين انھن کي الڳ جدول ۾ ذخيرو ڪريون ٿا.
اهو پڻ نوٽ ڪريو ته اسان جا سڀئي ٽيبل اڳ ۾ ئي ورهاڱي وارا آهن account_id. اهڙيء طرح، هڪ صورتحال جتي هڪ خاص طور تي وڏو اڪائونٽ ٻين لاء مسئلا پيدا ڪري ٿي خارج ٿيل آهي.
اشارا ڳولي رھيا آھن
ويجهي معائني تي، اسان ڏسون ٿا ته ڪجهه خاص درخواست سان غلط آهي. اهو هن لائن تي هڪ ويجهي نظر وٺڻ جي قابل آهي:
urls && array(
select id from acc_{account_id}.urls
where url ILIKE '%enterprise_customer.com/jobs%'
)::text[]
SELECT id FROM urls WHERE url ILIKE '%enterprise_customer.com/jobs%';
id
--------
...
(198661 rows)
Time: 5231.765 ms
ٽيمپليٽ جي ڳولا جي درخواست پاڻ کي صرف 5 سيڪنڊن ۾ وٺندي آهي. هڪ ملين منفرد URLs ۾ نموني ڳولڻ واضح طور تي ڪو مسئلو ناهي.
لسٽ تي ايندڙ مشڪوڪ ڪيترائي آهن JOIN. شايد انهن جو گهڻو استعمال سست رفتار جو سبب بڻيل آهي؟ عام طور تي JOINڪارڪردگي جي مسئلن لاء سڀ کان وڌيڪ واضح اميدوار آهن، پر مون کي يقين نه آيو ته اسان جو ڪيس عام هو.
analytics_db=# SELECT
count(*)
FROM
acc_{account_id}.urls as recordings_urls,
acc_{account_id}.recording_data_0 as recording_data,
acc_{account_id}.sessions_0 as sessions
WHERE
recording_data.usp_id = sessions.usp_id
AND sessions.referrer_id = recordings_urls.id
AND r_time > to_timestamp(1542585600)
AND r_time < to_timestamp(1545177599)
AND recording_data.duration >=5
AND recording_data.num_of_pages > 0 ;
count
-------
8086
(1 row)
Time: 147.851 ms
۽ اهو به اسان جو معاملو نه هو. JOINڪافي تيز ثابت ٿيو.
شڪ جي دائري کي تنگ ڪرڻ
مان ڪنهن به ممڪن ڪارڪردگي بهتري حاصل ڪرڻ لاءِ سوال کي تبديل ڪرڻ شروع ڪرڻ لاءِ تيار هوس. منهنجي ٽيم ۽ مون ترقي ڪئي 2 مکيه خيالن:
استعمال ڪريو EXISTS subquery URL لاءِ: اسان ٻيهر چيڪ ڪرڻ چاهيون ٿا ته ڇا URLs لاءِ ذيلي پڇاڙيءَ ۾ ڪو مسئلو آهي. هن کي حاصل ڪرڻ جو هڪ طريقو صرف استعمال ڪرڻ آهي EXISTS. EXISTSڪري سگهي ٿو ڪارڪردگي کي تمام گهڻو بهتر بڻائي ٿو ڇاڪاڻ ته اهو فوري طور تي ختم ٿي ويندو آهي جيئن ئي اهو صرف هڪ تار ڳولي ٿو جيڪو شرط سان ملندو آهي.
SELECT
count(*)
FROM
acc_{account_id}.urls as recordings_urls,
acc_{account_id}.recording_data as recording_data,
acc_{account_id}.sessions as sessions
WHERE
recording_data.usp_id = sessions.usp_id
AND ( 1 = 1 )
AND sessions.referrer_id = recordings_urls.id
AND (exists(select id from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com/jobs%'))
AND r_time > to_timestamp(1547585600)
AND r_time < to_timestamp(1549177599)
AND recording_data.duration >=5
AND recording_data.num_of_pages > 0 ;
count
32519
(1 row)
Time: 1636.637 ms
خير، ها. پڇا ڳاڇا جڏهن لپي وئي EXISTS، هر شي کي تمام تيز بڻائي ٿو. ايندڙ منطقي سوال آهي ڇو درخواست سان JOIN-امي ۽ ذيلي ذيلي خود انفرادي طور تي تيز آهن، پر گڏو گڏ تمام سست آهن؟
ذيلي سوال کي CTE ڏانهن منتقل ڪرڻ : جيڪڏهن سوال پنهنجو پاڻ تي تيز آهي، اسان آسانيءَ سان حساب ڪري سگھون ٿا تيزيءَ جو نتيجو پهريون ۽ پوءِ ان کي مهيا ڪري بنيادي سوال
WITH matching_urls AS (
select id::text from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com/jobs%'
)
SELECT
count(*) FROM acc_{account_id}.urls as recordings_urls,
acc_{account_id}.recording_data as recording_data,
acc_{account_id}.sessions as sessions,
matching_urls
WHERE
recording_data.usp_id = sessions.usp_id
AND ( 1 = 1 )
AND sessions.referrer_id = recordings_urls.id
AND (urls && array(SELECT id from matching_urls)::text[])
AND r_time > to_timestamp(1542585600)
AND r_time < to_timestamp(1545107599)
AND recording_data.duration >=5
AND recording_data.num_of_pages > 0;
پر اهو اڃا تائين تمام سست هو.
مجرم جي ڳولا
ان سڄي عرصي ۾، منهنجي اکين اڳيان هڪ ننڍڙي شيءِ چمڪي رهي هئي، جنهن کي مان مسلسل هڪ طرف ڇڪيندو رهيس. پر جيئن ته ٻيو ڪجهه به نه بچيو هو، تنهن ڪري مون به هن کي ڏسڻ جو فيصلو ڪيو. مان ڳالهائي رهيو آهيان && آپريٽر خدا حافظ EXISTS صرف بهتر ڪارڪردگي && سست سوال جي سڀني نسخن ۾ صرف باقي عام عنصر هو.
ڏسي رهيو آهي دستاويز، اسان اهو ڏسون ٿا && استعمال ڪيو ويندو آھي جڏھن توھان کي ٻن صفن جي وچ ۾ عام عنصر ڳولڻ جي ضرورت آھي.
اصل درخواست ۾ هي آهي:
AND ( urls && array(select id from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com/jobs%')::text[] )
جنهن جو مطلب آهي ته اسان پنهنجي URLs تي نمونن جي ڳولا ڪندا آهيون، پوءِ عام پوسٽن سان گڏ سڀني URLs سان چونڪ ڳوليندا آهيون. اهو ٿورڙو مونجهارو آهي ڇو ته هتي "urls" سڀني URLs تي مشتمل ٽيبل ڏانهن اشارو نه آهي، پر ٽيبل ۾ "urls" ڪالمن ڏانهن. recording_data.
جي حوالي سان وڌندڙ شڪ سان &&، مون انهن لاءِ تصديق ڳولڻ جي ڪوشش ڪئي سوال جي منصوبي ۾ ٺاهيل EXPLAIN ANALYZE (مون وٽ اڳ ۾ ئي هڪ منصوبو محفوظ ڪيو ويو هو، پر آئون عام طور تي SQL ۾ تجربا ڪرڻ کان وڌيڪ آرامده آهيان سوالن جي رٿابندي ڪندڙن جي مبهميت کي سمجهڻ جي ڪوشش ڪرڻ کان).
Filter: ((urls && ($0)::text[]) AND (r_time > '2018-12-17 12:17:23+00'::timestamp with time zone) AND (r_time < '2018-12-18 23:59:59+00'::timestamp with time zone) AND (duration >= '5'::double precision) AND (num_of_pages > 0))
Rows Removed by Filter: 52710
فلٽر جون ڪيتريون ئي لائينون هيون صرف مان &&. جنهن جو مطلب اهو ٿيو ته هي آپريشن نه رڳو مهانگو هو، پر ڪيترائي ڀيرا ڪيو ويو.
مون هن حالت کي الڳ ڪري آزمايو
SELECT 1
FROM
acc_{account_id}.urls as recordings_urls,
acc_{account_id}.recording_data_30 as recording_data_30,
acc_{account_id}.sessions_30 as sessions_30
WHERE
urls && array(select id from acc_{account_id}.urls where url ILIKE '%enterprise_customer.com/jobs%')::text[]
اهو صرف هڪ اهم آپريشن آهي. اسان کي هميشه URLs جي پوري ھيٺئين جدول کي ڳولڻ جي ضرورت آھي ھڪڙو نمونو ڳولڻ لاءِ، ۽ اسان کي ھميشه چوڪن کي ڳولڻ جي ضرورت آھي. اسان URL رڪارڊ ذريعي سڌو سنئون نه ڳولي سگهون ٿا، ڇاڪاڻ ته اهي صرف IDs جو حوالو ڏئي رهيا آهن urls.
مون استعمال ڪرڻ کان سواءِ پوسٽ گريس ۾ چونڪ سيٽ ڪرڻ جو رستو ڳولڻ شروع ڪيو &&، پر گهڻي ڪاميابي کان سواءِ.
آخر ۾، اسان فيصلو ڪيو ته صرف اڪيلائي ۾ مسئلو حل ڪريو: مون کي سڀ ڪجهه ڏيو urls سٽون جن لاءِ URL نموني سان ملندو آهي. بغير اضافي شرطن جي اهو ٿيندو -
SELECT urls.url
FROM
acc_{account_id}.urls as urls,
(SELECT unnest(recording_data.urls) AS id) AS unrolled_urls
WHERE
urls.id = unrolled_urls.id AND
urls.url ILIKE '%jobs%'
بدران JOIN نحو مون صرف هڪ ذيلي سوال استعمال ڪيو ۽ وڌايو recording_data.urls array ته جيئن توھان سڌو سنئون شرط لاڳو ڪري سگھوٿا WHERE.
هتي سڀ کان اهم شيء اها آهي && چيڪ ڪرڻ لاءِ استعمال ڪيو ويو ته ڇا ڏنل داخلا هڪ ملندڙ URL تي مشتمل آهي. جيڪڏهن توهان ٿورو غور ڪيو ته توهان ڏسي سگهو ٿا ته هي آپريشن هڪ صف جي عناصر (يا ٽيبل جي قطار) جي ذريعي هلندو آهي ۽ بند ٿي ويندو آهي جڏهن هڪ شرط (ميچ) ملندي آهي. ڇا توهان کي ڪجهه به ياد نه ٿو اچي؟ ها، EXISTS.
کان وٺي recording_data.urls ذيلي سوال جي حوالي سان ٻاهران حوالو ڏئي سگهجي ٿو، جڏهن اهو ٿئي ٿو ته اسان پنهنجي پراڻي دوست تي واپس اچي سگهون ٿا EXISTS ۽ ان سان گڏ سبسڪرپشن لپي.
سڀڪنھن شيء کي گڏ ڪرڻ، اسان کي حتمي اصلاحي سوال حاصل ڪريون ٿا:
SELECT
count(*)
FROM
acc_{account_id}.urls as recordings_urls,
acc_{account_id}.recording_data as recording_data,
acc_{account_id}.sessions as sessions
WHERE
recording_data.usp_id = sessions.usp_id
AND ( 1 = 1 )
AND sessions.referrer_id = recordings_urls.id
AND r_time > to_timestamp(1542585600)
AND r_time < to_timestamp(1545177599)
AND recording_data.duration >=5
AND recording_data.num_of_pages > 0
AND EXISTS(
SELECT urls.url
FROM
acc_{account_id}.urls as urls,
(SELECT unnest(urls) AS rec_url_id FROM acc_{account_id}.recording_data)
AS unrolled_urls
WHERE
urls.id = unrolled_urls.rec_url_id AND
urls.url ILIKE '%enterprise_customer.com/jobs%'
);
۽ آخري ليڊ ٽائيم Time: 1898.717 ms جشن ملهائڻ جو وقت؟!؟
ايترو جلدي نه! پهرين توهان کي درست ڪرڻ جي جانچ ڪرڻ جي ضرورت آهي. مون کي ڏاڍي شڪ هئي EXISTS اصلاح جيئن اڳ ختم ڪرڻ جي منطق کي تبديل ڪري ٿي. اسان کي پڪ ڪرڻ جي ضرورت آهي ته اسان درخواست ۾ غير واضح غلطي شامل نه ڪئي آهي.
هڪ سادي آزمائش ڊوڙندو هو count(*) مختلف ڊيٽا سيٽ جي وڏي تعداد لاء سست ۽ تيز سوالن تي. ان کان پوء، ڊيٽا جي ننڍڙي ذيلي سيٽ لاء، مون دستي طور تي تصديق ڪئي ته سڀئي نتيجا صحيح هئا.
اسان ~ 24 منٽ کان 2 سيڪنڊن جي سوال جي وقت کان وياسون - ڪافي ڪارڪردگي واڌارو! جيتوڻيڪ هي مضمون وڏو نڪتو، سڀ تجربا اسان هڪ ڏينهن ۾ ڪيا، ۽ اندازو لڳايو ويو ته انهن کي بهتر ڪرڻ ۽ جانچ ڪرڻ لاءِ 1,5 ۽ 2 ڪلاڪ لڳا.
SQL هڪ شاندار ٻولي آهي جيڪڏهن توهان ان کان نه ڊڄو، پر ان کي سکڻ ۽ استعمال ڪرڻ جي ڪوشش ڪريو. چڱيءَ ريت سمجھڻ سان ته SQL سوالن تي عمل ڪيئن ڪيو وڃي ٿو، ڊيٽابيس سوالن جا منصوبا ڪيئن ٺاھي ٿو، انڊيڪس ڪيئن ڪم ڪن ٿا، ۽ صرف ڊيٽا جي سائيز جنھن سان توھان ڊيل ڪري رھيا آھيو، توھان تمام ڪامياب ٿي سگھوٿا سوالن کي بهتر ڪرڻ ۾. اهو ساڳيو ضروري آهي، تنهن هوندي، مختلف طريقن جي ڪوشش جاري رکڻ ۽ دير سان مسئلو کي ٽوڙڻ، رڪاوٽون ڳولڻ.
اهڙن نتيجن کي حاصل ڪرڻ جي باري ۾ بهترين حصو قابل ذڪر، ڏسڻ واري رفتار جي بهتري آهي - جتي هڪ رپورٽ جيڪا اڳ ۾ به لوڊ نه ٿيندي هئي هاڻي لڳ ڀڳ فوري طور تي لوڊ ٿئي ٿي.
جي خاص مهرباني منهنجا ساٿي آدتيه مشرا جي حڪم تي, آديت گورو и ورون ملهوترا ذهن سازي لاءِ ۽ دنڪر پندر اسان جي آخري درخواست ۾ هڪ اهم غلطي ڳولڻ کان اڳ اسان آخرڪار ان کي الوداع چيو!