प्रत्येक परिनियोजन में, हमेशा कुछ प्रश्न होते हैं जो बहुत धीमी गति से चलते हैं।
यह देखने के लिए पढ़ें कि जिन प्रश्नों को निष्पादित करने में बहुत अधिक समय लगता है उन्हें कैसे खोजा जाए और यह कैसे पता लगाया जाए कि वे धीमे क्यों हैं।
बस pg_stat_statements का उपयोग करें?
pg_stat_statements एक लोकप्रिय एक्सटेंशन है जो कोर पोस्टग्रेएसक्यूएल वितरण में शामिल है और लगभग सभी डीबीएएएस प्रदाताओं पर डिफ़ॉल्ट रूप से उपलब्ध है। यह अमूल्य है, और कमोबेश कस्टम एक्सटेंशन इंस्टॉल किए बिना प्रश्नों पर आंकड़े प्राप्त करने का एकमात्र तरीका है।
हालांकि, धीमी क्वेरी की खोज में इसकी कुछ सीमाएं हैं।
संचयी आंकड़े
pg_stat_statements एक्सटेंशन संचयी प्रदान करता है सर्वर द्वारा निष्पादित प्रत्येक क्वेरी के बारे में आंकड़े। प्रत्येक क्वेरी के लिए, यह अन्य मेट्रिक्स के बीच, इसे कितनी बार निष्पादित किया गया है, और सभी निष्पादनों में लिया गया कुल समय दिखाता है।
धीमी क्वेरी के होने पर "पकड़ने" के लिए, आपको समय-समय पर pg_stat_statements
की संपूर्ण सामग्री प्राप्त करने की आवश्यकता होती है देखें, इसे टाइमसीरीज डेटाबेस में स्टोर करें, और निष्पादन गणना की तुलना करें। उदाहरण के लिए, यदि आपके पास 10.00 पूर्वाह्न और 10.10 बजे pg_stat_statements की सामग्री है, तो आप उन प्रश्नों का चयन कर सकते हैं जिनकी निष्पादन संख्या 10.10 पूर्वाह्न से 10.10 बजे अधिक है। इन प्रश्नों के लिए, आप इस अंतराल के दौरान औसत निष्पादन समय की गणना निम्न का उपयोग करके कर सकते हैं:
(total time at 10.10 AM - total time at 10.00 AM) ÷ (total count at 10.10 AM - total count at 10.00 AM)
यदि यह औसत निष्पादन समय ऊपरी सीमा से अधिक है, तो आप कार्रवाई करने के लिए अलर्ट ट्रिगर कर सकते हैं।
यह व्यवहार में काफी अच्छी तरह से काम करता है, लेकिन आपको एक अच्छी निगरानी अवसंरचना, या pgDash जैसी समर्पित सेवा की आवश्यकता होगी।
क्वेरी पैरामीटर
pg_stat_statements क्वेरीज़ को पास किए गए बाइंड पैरामीटर के मानों को कैप्चर नहीं करता है।
एक निष्पादन योजना का चयन करने के लिए पोस्टग्रेज क्वेरी प्लानर का अनुमान लगाने वाली चीजों में से एक यह है कि एक शर्त को फ़िल्टर करने की संभावना वाली पंक्तियों की संख्या है। उदाहरण के लिए यदि किसी तालिका की अधिकांश पंक्तियों में एक अनुक्रमित स्तंभ का मान है देश "यूएस" के रूप में, योजनाकार अनुक्रमिक स्कैन . करने का निर्णय ले सकता है कहां . के लिए संपूर्ण तालिका का खंड country = "US"
, और एक इंडेक्स स्कैन . का उपयोग करने का निर्णय ले सकता है country = "UK"
. के लिए पहले कहां . से क्लॉज के तालिका में अधिकांश पंक्तियों से मेल खाने की उम्मीद है।
उन मापदंडों के वास्तविक मूल्य को जानने के लिए जिनके लिए क्वेरी निष्पादन धीमा था, धीमी क्वेरी समस्याओं का तेजी से निदान करने में मदद कर सकता है।
स्लो क्वेरी लॉगिंग
धीमे प्रश्नों को लॉग करना आसान विकल्प है। एक निश्चित अन्य DBMS के विपरीत जो इसे आसान बनाता है, PostgreSQL हमें समान दिखने वाली कॉन्फ़िगरेशन सेटिंग्स का एक समूह प्रस्तुत करता है:
log_statement
log_min_duration_statement
log_min_duration_sample
log_statement_sample_rate
log_parameter_max_length
log_parameter_max_length_on_error
log_duration
इन्हें पोस्टग्रेज प्रलेखन में विस्तार से वर्णित किया गया है। यहां एक उचित प्रारंभिक बिंदु है:
# next line says only log queries that take longer 5 seconds
log_min_duration_statement = 5s
log_parameter_max_length = 1024
log_parameter_max_length_on_error = 1024
जिसके परिणामस्वरूप इस तरह के लॉग होते हैं:
2022-04-14 06:17:11.462 UTC [369399] LOG: duration: 5.060 ms statement: select i.*, t."Name" as track, ar."Name" as artist
from "InvoiceLine" as i
join "Track" as t on i."TrackId" = t."TrackId"
join "Album" as al on al."AlbumId" = t."AlbumId"
join "Artist" as ar on ar."ArtistId" = al."ArtistId";
यदि बहुत अधिक लॉग हैं, तो आप Postgres को केवल लॉग करने के लिए कह सकते हैं (कहते हैं) 50% क्वेरी जो 5 सेकंड से अधिक समय तक चलती हैं:
log_min_duration_sample = 5s
log_statement_sample_rate = 0.5 # 0..1 => 0%..100%
आपको निश्चित रूप से डॉक्स के माध्यम से पढ़ना चाहिए कि इन मापदंडों का क्या मतलब है और उन्हें अपने पोस्टग्रेज कॉन्फ़िगरेशन में जोड़ने से पहले। सावधान रहें कि सेटिंग्स विचित्र और गैर-अंतर्ज्ञानी हैं।
धीमी क्वेरी की निष्पादन योजनाएं
आमतौर पर यह जानना पर्याप्त नहीं है कि एक धीमी क्वेरी हुई, आपको यह भी पता लगाना होगा कि क्यों यह धीमा था। इसके लिए, आप आमतौर पर पहले क्वेरी की निष्पादन योजना की जांच करेंगे।
auto_explain
एक और कोर पोस्टग्रेएसक्यूएल एक्सटेंशन है (फिर से, अधिकांश डीबीएएएस पर भी उपलब्ध है) जो उन प्रश्नों की निष्पादन योजनाओं को लॉग कर सकता है जिन्होंने अभी निष्पादन समाप्त किया है। यह यहाँ प्रलेखित है।
auto_explain को सक्षम करने के लिए, आप आमतौर पर इसे shared_preload_libraries
में जोड़ते हैं और पोस्टग्रेज को पुनरारंभ करें। यहां एक नमूना स्टार्टर कॉन्फ़िगरेशन दिया गया है:
# logs execution plans of queries that take 10s or more to run
auto_explain.log_min_duration = 10s
auto_explain.log_verbose = on
auto_explain.log_settings = on
auto_explain.log_format = json
auto_explain.log_nested_statements = on
# enabling these provide more information, but have a performance cost
#auto_explain.log_analyze = on
#auto_explain.log_buffers = on
#auto_explain.log_wal = on
#auto_explain.log_timing = on
#auto_explain.log_triggers = on
इससे योजनाओं को JSON प्रारूप के रूप में लॉग किया जाएगा, जिसे बाद में इन जैसे टूल में देखा जा सकता है।
स्टिल-एक्ज़ीक्यूटिंग क्वेरीज़
ऊपर सूचीबद्ध सभी तकनीकों में एक बात समान है:वे केवल बाद . क्रिया योग्य आउटपुट उत्पन्न करती हैं एक क्वेरी ने निष्पादन समाप्त कर दिया है। उनका उपयोग उन प्रश्नों को संभालने के लिए नहीं किया जा सकता है जो इस बार इतने धीमे हैं, कि उन्होंने अभी तक निष्पादन समाप्त नहीं किया है।
PostgreSQL सर्वर से प्रत्येक कनेक्शन को बैकएंड . द्वारा नियंत्रित किया जाता है , विशेष रूप से एक क्लाइंट बैकएंड . जब ऐसा बैकएंड किसी क्वेरी को निष्पादित कर रहा हो, तो उसकी स्थिति सक्रिय होती है . हो सकता है कि इसने एक लेन-देन भी शुरू कर दिया हो, लेकिन फिर निष्क्रिय हो जाता है, जिसे लेन-देन में निष्क्रिय . कहा जाता है राज्य।
pg_stat_activity
यहां प्रलेखित सिस्टम व्यू सभी चल रहे पोस्टग्रेज बैकएंड की एक सूची साबित करता है। आप अभी भी चल रहे प्रश्नों को प्राप्त करने के लिए इस दृश्य को क्वेरी कर सकते हैं:
SELECT client_addr, query_start, query
FROM pg_stat_activity
WHERE state IN ('active', 'idle in transaction')
AND backend_type = 'client backend';
वैसे, तृतीय-पक्ष एक्सटेंशन का उपयोग किए बिना, किसी क्वेरी की निष्पादन योजना को जानने का कोई तरीका नहीं है जिसे वर्तमान में बैकएंड द्वारा निष्पादित किया जा रहा है।
ताले
यदि धीमी क्वेरी की निष्पादन योजना किसी स्पष्ट समस्या का संकेत नहीं देती है, तो हो सकता है कि क्वेरी को निष्पादित करने वाला बैकएंड विवादित ताले द्वारा विलंबित हो गया हो।
विभिन्न कारणों से क्वेरी निष्पादन के दौरान या तो स्पष्ट रूप से या परोक्ष रूप से ताले प्राप्त किए जाते हैं। इसके लिए समर्पित पोस्टग्रेज़ दस्तावेज़ीकरण में एक पूरा अध्याय है।
लॉगिंग लॉक
आमतौर पर, lock_timeout . विकल्प का उपयोग करके कितनी देर तक प्रतीक्षा करनी है, इसकी ऊपरी सीमा निर्धारित की जाती है , आमतौर पर क्लाइंट साइड पर। यदि कोई क्वेरी लॉक प्राप्त करने के लिए लंबे समय से प्रतीक्षा कर रही है, तो Postgres इस क्वेरी के निष्पादन को रद्द कर देगा और एक त्रुटि लॉग करेगा:
2021-01-30 09:35:52.415 UTC [67] psql postgres testdb 172.17.0.1 ERROR: canceling statement due to lock timeout
2021-01-30 09:35:52.415 UTC [67] psql postgres testdb 172.17.0.1 STATEMENT: cluster t;
मान लें कि आप 1 मिनट का लॉक टाइमआउट सेट करना चाहते हैं, लेकिन लॉग क्वेरी जो लॉक के लिए 30 सेकंड से अधिक समय तक प्रतीक्षा करती हैं। आप इसका उपयोग करके ऐसा कर सकते हैं:
log_lock_waits = on
deadlock_timeout = 30s
यह इस तरह के लॉग बनाएगा:
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 LOG: process 70 still waiting for ShareLock on transaction 493 after 30009.004 ms
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 DETAIL: Process holding the lock: 68. Wait queue: 70.
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 CONTEXT: while locking tuple (0,3) in relation "t"
2021-01-30 09:49:22.331 UTC [70] psql postgres testdb 172.17.0.1 STATEMENT: select * from t for update;
deadlock_timeout . का उपयोग टाइपो नहीं है:यह वह मान है जो लॉक प्रतीक्षा लॉगिंग तंत्र का उपयोग करता है। आदर्श रूप से, कुछ ऐसा होना चाहिए था जैसे log_min_duration_lock_wait , लेकिन दुर्भाग्य से, ऐसा नहीं है।
वास्तविक गतिरोध के मामले में, Postgres गतिरोध वाले लेन-देन को deadlock_timeout के बाद निरस्त कर देगा अवधि, और आपत्तिजनक बयानों को लॉग करेगा। कोई स्पष्ट कॉन्फ़िगरेशन आवश्यक नहीं है।
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 LOG: process 68 detected deadlock while waiting for ShareLock on transaction 496 after 30007.633 ms
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 DETAIL: Process holding the lock: 70. Wait queue: .
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 CONTEXT: while locking tuple (0,3) in relation "t"
2021-01-30 09:55:37.724 UTC [68] psql postgres testdb 172.17.0.1 STATEMENT: select * from t where a=4 for update;
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 ERROR: deadlock detected
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 DETAIL: Process 68 waits for ShareLock on transaction 496; blocked by process 70.
Process 70 waits for ShareLock on transaction 495; blocked by process 68.
Process 68: select * from t where a=4 for update;
Process 70: select * from t where a=0 for update;
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 HINT: See server log for query details.
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 CONTEXT: while locking tuple (0,3) in relation "t"
2021-01-30 09:55:37.725 UTC [68] psql postgres testdb 172.17.0.1 STATEMENT: select * from t where a=4 for update;
वर्तमान ताले की खोज करना
वर्तमान में दिए गए तालों की पूरी सूची pg_locks सिस्टम दृश्य से उपलब्ध है। हालांकि, pg_blocking_pids
. फ़ंक्शन का उपयोग करना आम तौर पर आसान होता है , साथ में pg_stat_activity
, इस तरह:
SELECT state, pid, pg_blocking_pids(pid), query
FROM pg_stat_activity
WHERE backend_type='client backend';
जो इस तरह का आउटपुट दिखा सकता है:
state | pid | pg_blocking_pids | query
---------------------+--------+------------------+-------------------------------------------------
active | 378170 | {} | SELECT state, pid, pg_blocking_pids(pid), query+
| | | FROM pg_stat_activity +
| | | WHERE backend_type='client backend';
active | 369399 | {378068} | cluster "Track";
idle in transaction | 378068 | {} | select * from "Track" for update;
(3 rows)
जो इंगित करता है कि एक बैकएंड है जो अवरुद्ध है (क्लस्टर स्टेटमेंट निष्पादित करने वाला), और इसे पीआईडी 378068 द्वारा अवरुद्ध किया जा रहा है (जिसने एक चयन निष्पादित किया है .. अद्यतन के लिए लेकिन फिर लेनदेन के भीतर निष्क्रिय है)।