तपाईंको रिपोर्ट डेटाबेस होस्टमा करिब एक सेकेन्डमा र VPN मार्फत चारमा सकिन्छ, र psql ले छाप्ने संख्या सिधै डेटाबेसतर्फ देखाउँछ। त्यो संख्या क्लाइन्ट पक्षको स्टपवाच हो, सर्भरको मापन होइन। यसले स्टेटमेन्टको बाहिर जाने बाटो, उत्तरको प्रतीक्षा र फर्कने पङ्क्तिहरू समेट्छ। यी तीनलाई छुट्याउनु नै कुन पक्ष ट्युन गर्ने भन्ने थाहा पाउने एकमात्र उपाय हो।

psql टाइमरले वास्तवमा के मापन गर्छ

\timing on क्लाइन्टले स्टेटमेन्ट सकेटमा लेख्नुअघि नै स्टपवाच सुरु गर्छ र त्यो नतिजाको अन्तिम पङ्क्ति पढिएपछि रोक्छ। सर्भरको आफ्नै कार्यान्वयन त्यो विन्डोभित्र कतै छ, र प्याकेटले टनेलमा बिताउने प्रत्येक मिलिसेकेन्ड पनि। आउटपुटमा केहीले पनि तिनलाई छुट्याउँदैन। EXPLAIN ले पनि संख्या छाप्छ, तर त्यो सर्भरले बनाउँछ र क्लाइन्टको प्रतीक्षा बाहिर राख्छ। दुई संख्या, दुई फरक प्रश्न।

एउटा सत्र सुरु गर्नुहोस्, समय मापन खुला राख्नुहोस्, र चासोको स्टेटमेन्ट त्यसैभित्रबाट चलाउनुहोस्। सत्र पुनः प्रयोग गर्दा जडानको लागत पहिलो मापनबाहिर रहन्छ।

psql "host=db.internal port=5432 dbname=appdb user=app" \
  -c "\timing on" \
  -c "select count(*) from orders where created_at > now() - interval '1 day';"

संख्यामा अझै नतिजाको स्थानान्तरण समावेश छ, जुन यहाँ चाहिएको हो। नयाँ कलले थप्ने जडान र प्रमाणीकरण आदानप्रदान अब यसमा छैन।

एउटा स्टेटमेन्टलाई तीन बाटोमा तुलना गर्नुहोस्

त्यही स्टेटमेन्ट Unix सकेट, LAN ठेगाना र VPN होस्ट नामबाट चलाउनुहोस् र तीनको तुलना गर्नुहोस्। यदि अन्तिम मात्र ढिलो छ भने, क्वेरी परिवर्तनशील होइन।

प्रत्येक कल पहिले जडान हुन्छ र त्यसपछि मात्र स्टेटमेन्ट मापन गर्छ, त्यसैले जडानको लागत संख्याबाहिर रहन्छ भने स्थानान्तरण भित्र रहन्छ। WHERE खण्ड, पङ्क्ति संख्या र क्लाइन्ट मेसिन समान राख्नुहोस्, नत्र तपाईं बाटो होइन, कामको भार तुलना गर्दै हुनुहुन्छ।

psql -h /var/run/postgresql -U app -d appdb -c "\timing on" -c "select count(*) from orders;"
psql -h 10.40.0.12 -U app -d appdb -c "\timing on" -c "select count(*) from orders;"
psql -h db.vpn.internal -U app -d appdb -c "\timing on" -c "select count(*) from orders;"

LAN मा फरक सामान्यतया बेवास्ता गर्न सकिने जत्तिकै सानो हुन्छ; VPN मार्फत धेरै पटक हुँदैन। तीन नतिजा क्रमबद्ध गर्दा कुन प्रतीक्षामा आक्रमण गर्ने भन्ने थाहा हुन्छ।

ढिलो स्थानीय सकेट भनेको सर्भरको काम वा योजना। ढिलो LAN नतिजा भनेको क्वेरी वा यसले सार्ने परिमाण। VPN नतिजा मात्र ढिलो हुनु भनेको बाटोमा ढिलाइ, MTU वा उपलब्ध ब्यान्डविथ, र कुनै इन्डेक्स परिवर्तनले त्यो सुधार्दैन।

सर्भरको आफ्नै कार्यान्वयन समय निकाल्नुहोस्

सर्भरले कति समय खर्च गर्यो भनी बताउन सक्छ, र क्लाइन्टको संख्यासँग तुलना गर्नुपर्ने संख्या त्यही हो। ANALYZE सहित EXPLAIN ले स्टेटमेन्ट चलाउँछ र योजनाभित्र योजना र कार्यान्वयन समय छाप्छ, जबकि BUFFERS ले क्यास व्यवहार थप्छ जसले तातो दौडलाई चिसोसँग तुलना गर्दा प्रायः व्याख्या गर्छ। लेख्ने इरादा छैन भने यसलाई लेखन स्टेटमेन्टतर्फ नलगाउनुहोस्। पढ्नका लागि मात्रको प्रतिलिपिमा सुरु गर्ने सबैभन्दा सुरक्षित ठाउँ यही हो, र psql सन्दर्भ टाइमरको क्लाइन्ट पक्षको दायरा अभिलेख गर्छ।

एप्लिकेसनले पहिले नै चलाउने स्टेटमेन्टका लागि, pg_stat_statements ले केही पनि फेरि नचलाई सर्भर पक्षको कार्यान्वयन एकत्र गर्छ। पङ्क्तिहरू सामान्यीकृत क्वेरीअनुसार हुन्छन्, त्यसैले एउटा प्रविष्टिले धेरै कल स्थान ढाक्न सक्छ।

select calls, round(mean_exec_time::numeric, 2) as mean_ms, rows
from pg_stat_statements
order by mean_exec_time desc
limit 5;

स्तम्भका नाम संस्करणअनुसार फरक पर्छन्: PostgreSQL 13 र त्यसपछिका mean_exec_time देखाउँछन्, पुराना संस्करणले यसलाई mean_time भन्छन्, त्यसैले जाँच्नुहोस् \d pg_stat_statements ले, यदि त्यो क्वेरीले त्रुटि दिन्छ। यी मानहरूले योजना बाहिर राख्छन् र तपाईंको क्लाइन्टसम्मको यात्रा पनि बाहिर राख्छन्। यही बहिष्कारले तिनलाई तुलनाका लागि उपयोगी बनाउँछ।

आउने-जाने गन्ती गर्नुहोस्, मात्र मिलिसेकेन्ड होइन

दुई सय साना निर्भर स्टेटमेन्टले बनेको रिपोर्टले बाटोले थप्ने जुनसुकै ढिलाइलाई दुई सयले गुणन गर्छ। दस लाख पङ्क्ति फर्काउने एउटा स्टेटमेन्टले त्यो ढिलाइ एक पटक तिर्छ र त्यसपछि लामो समय ब्यान्डविथ तिर्छ। दुवै क्लाइन्ट टाइमरमा उस्तै देखिन्छन्, र दुवैलाई विपरीत सुधार चाहिन्छ।

स्टेटमेन्टको संख्या अनुमान नगरी मापन गर्नुहोस्। कुल पढ्नुहोस्, रिपोर्ट एक पटक चलाउनुहोस्, फेरि पढ्नुहोस् र घटाउनुहोस्।

select sum(calls) as calls from pg_stat_statements;
-- run the report here
select sum(calls) as calls from pg_stat_statements;

यदि डेल्टा ठूलो छ र सर्भरमा प्रत्येक स्टेटमेन्ट सस्तो छ भने, ब्याचिङ त्यो सुधार हो जसले फल दिन्छ। निर्भर क्वेरी मिलाउनुहोस्, एउटा सेट-आधारित स्टेटमेन्ट प्रयोग गर्नुहोस्, वा कर्सरबाट लूप चलाउनुहोस्। अन्तरक्रियात्मक psql मा, \set FETCH_COUNT 1000 ठूलो नतिजा ब्याचमा आउन दिन्छ र स्थानान्तरण तथा क्लाइन्ट मेमोरीको व्यवहार बदल्छ। यसले सर्भरको काम घटाउँदैन, त्यसैले ढिलो क्वेरी बचाउँदैन।

टनेललाई पुनःप्रेषण र MTU अवरोधका लागि जाँच्नुहोस्

जब साना स्टेटमेन्ट छिटो हुन्छन् र ठूला नतिजा आधा बाटोमा रोकिन्छन्, क्वेरी सामान्यतया ठीक हुन्छ र बाटो हुँदैन। MTU आधारभूत लिङ्कभन्दा कम भएको टनेल, अवरुद्ध ICMP सँग मिल्दा ठ्याक्कै त्यही ढाँचा बन्छ: पहिलो प्याकेट आउँछन्, ठूला हराउँछन्, र फेरि प्रयास नगरेसम्म स्थानान्तरण झुन्डिन्छ। क्लाइन्ट पक्षका पुनःप्रेषण काउन्टरले त्यो देखाउँछन्।

जानाजान ढिलो स्थानान्तरण चलिरहेको बेला सकेट र कर्नेल काउन्टर हेर्नुहोस्। पुनःप्रेषणका जोड संचयी हुन्छन्, त्यसैले एउटा नमुना पढ्नुको सट्टा अघि र पछि टिप्नुहोस्।

ss -tin dst 10.40.0.12
netstat -s | grep -iE "retransmit|segments retransmitted"
ping -M do -s 1400 -c 3 10.40.0.12

स्थानान्तरणका क्रममा बढ्ने पुनःप्रेषण, 1400 बाइटमा सफल तर 1472 मा असफल हुने ping सँगै, डेटाबेस समस्या होइन MTU समस्या देखाउँछन्। टनेल इन्टरफेसको MTU घटाउनु वा गेटवेमा MSS थिच्नु सामान्य सुधार हो, र तीही तीन आदेशले पछि पुष्टि गर्छन्। स्थानान्तरण अझै ढिलो हुँदा पुनःप्रेषण समतल रह्यो भने, हानितर्फ होइन टनेललाई दिइएको ब्यान्डविथतर्फ हेर्नुहोस्।

छोटो क्रमले अर्को ढिलो रिपोर्ट ढाक्छ: एउटा स्टेटमेन्ट स्थानीय, LAN मा र VPN मार्फत तुलना गर्नुहोस्; EXPLAIN वा pg_stat_statements बाट सर्भर कार्यान्वयन पढ्नुहोस्; एक पटक चलाउनुअघि र पछि कल गन्नुहोस्; र ठूलो नतिजा सर्दै गर्दा पुनःप्रेषण हेर्नुहोस्। प्रत्येक चरणले बाटोको एउटा पक्ष बाहिर राख्छ। तीमध्ये कुनैले पनि कुन कम्पोनेन्ट पुनः सुरु गर्ने अनुमान गर्न भन्दैन।

सम्बन्धित लेखहरू