PostgreSQL में बड़ी तालिकाओं में पंक्तियों की गिनती धीमी मानी जाती है। एमवीसीसी मॉडल को सटीक संख्या के लिए लाइव पंक्तियों की पूरी गणना की आवश्यकता होती है। इसे नाटकीय रूप से तेज़ करने . के समाधान हैं अगर गिनती नहीं करती है सटीक . होना चाहिए जैसा आपके मामले में लगता है।
(याद रखें कि आगमन पर "सटीक" गिनती भी संभावित रूप से मृत हो जाती है!)
सटीक गणना
धीमा बड़ी तालिकाओं के लिए।
समवर्ती लेखन कार्यों के साथ, यह आपके मिलते ही पुराना हो सकता है।
SELECT count(*) AS exact_count FROM myschema.mytable;
अनुमान
बेहद तेज़ :
SELECT reltuples AS estimate FROM pg_class where relname = 'mytable';
आमतौर पर, अनुमान बहुत करीब है। कितना करीब है, इस पर निर्भर करता है कि ANALYZE
या VACUUM
पर्याप्त चलाए जाते हैं - जहां "पर्याप्त" आपकी तालिका में लिखने की गतिविधि के स्तर से परिभाषित होता है।
सुरक्षित अनुमान
उपरोक्त एक डेटाबेस में एक ही नाम के साथ कई तालिकाओं की संभावना को अनदेखा करता है - विभिन्न स्कीमा में। इसका हिसाब देने के लिए:
SELECT c.reltuples::bigint AS estimate
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'mytable'
AND n.nspname = 'myschema';
bigint
. पर कास्ट करें real
. को फ़ॉर्मैट करता है संख्या अच्छी तरह से, विशेष रूप से बड़ी संख्या के लिए।
बेहतर अनुमान
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'myschema.mytable'::regclass;
तेज़, सरल, सुरक्षित, अधिक सुरुचिपूर्ण। वस्तु पहचानकर्ता प्रकार पर मैनुअल देखें।
बदलें 'myschema.mytable'::regclass
to_regclass('myschema.mytable')
. के साथ अमान्य तालिका नामों के अपवाद के बजाय कुछ भी नहीं पाने के लिए पोस्टग्रेज 9.4+ में। देखें:
- किसी दिए गए स्कीमा में तालिका मौजूद है या नहीं, इसकी जांच कैसे करें
अभी तक बेहतर अनुमान (बहुत कम अतिरिक्त लागत के लिए)
हम वही कर सकते हैं जो पोस्टग्रेज प्लानर करता है। पंक्ति अनुमान उदाहरण . का हवाला देते हुए मैनुअल में:
<ब्लॉकक्वॉट>
ये नंबर पिछले VACUUM
. के अनुसार वर्तमान हैं या ANALYZE
मेज पर। योजनाकार तब तालिका में पृष्ठों की वास्तविक वर्तमान संख्या प्राप्त करता है (यह एक सस्ता ऑपरेशन है, जिसमें टेबल स्कैन की आवश्यकता नहीं होती है)। अगर यह relpages
. से अलग है फिर reltuples
वर्तमान संख्या-की-पंक्तियों के अनुमान पर पहुंचने के लिए तदनुसार स्केल किया गया है।
पोस्टग्रेज estimate_rel_size
. का उपयोग करता है src/backend/utils/adt/plancat.c
में परिभाषित , जिसमें pg_class
. में कोई डेटा नहीं होने के कॉर्नर केस को भी शामिल किया गया है क्योंकि रिश्ता कभी खाली नहीं होता। हम SQL में कुछ ऐसा ही कर सकते हैं:
न्यूनतम रूप
SELECT (reltuples / relpages * (pg_relation_size(oid) / 8192))::bigint
FROM pg_class
WHERE oid = 'mytable'::regclass; -- your table here
सुरक्षित और मुखर
SELECT (CASE WHEN c.reltuples < 0 THEN NULL -- never vacuumed
WHEN c.relpages = 0 THEN float8 '0' -- empty table
ELSE c.reltuples / c.relpages END
* (pg_relation_size(c.oid) / pg_catalog.current_setting('block_size')::int)
)::bigint
FROM pg_class c
WHERE c.oid = 'myschema.mytable'::regclass; -- schema-qualified table here
खाली टेबल और टेबल से टूटता नहीं है जिन्होंने कभी VACUUM
नहीं देखा है या ANALYZE
. pg_class
. पर मैनुअल :
यदि तालिका को अभी तक वैक्यूम या विश्लेषण नहीं किया गया है, तो reltuples
इसमें -1
शामिल है यह दर्शाता है कि पंक्ति संख्या अज्ञात है।
अगर यह क्वेरी NULL
लौटाती है , ANALYZE
चलाएं या VACUUM
तालिका के लिए और दोहराएँ। (वैकल्पिक रूप से, आप पोस्टग्रेज जैसे कॉलम प्रकारों के आधार पर पंक्ति की चौड़ाई का अनुमान लगा सकते हैं, लेकिन यह थकाऊ और त्रुटि-प्रवण है।)
अगर यह क्वेरी 0
returns लौटाती है , तालिका खाली प्रतीत होती है। लेकिन मैं ANALYZE
करूंगा सुनिश्चित करना। (और शायद अपना autovacuum
जांचें सेटिंग्स।)
आमतौर पर, block_size
8192 है। current_setting('block_size')::int
दुर्लभ अपवादों को शामिल करता है।
तालिका और स्कीमा योग्यताएं इसे किसी भी search_path
. से प्रतिरक्षित बनाती हैं और दायरा।
किसी भी तरह, क्वेरी लगातार मेरे लिए <0.1 एमएस लेती है।
अधिक वेब संसाधन:
- द पोस्टग्रेज विकी अक्सर पूछे जाने वाले प्रश्न
- गणना अनुमानों और गणना(*) प्रदर्शन के लिए विकि पृष्ठों को पोस्टग्रेज करता है
TABLESAMPLE SYSTEM (n)
पोस्टग्रेज में 9.5+
SELECT 100 * count(*) AS estimate FROM mytable TABLESAMPLE SYSTEM (1);
जैसे @a_horse ने टिप्पणी की, SELECT
. के लिए जोड़ा गया क्लॉज कमांड उपयोगी हो सकता है यदि pg_class
. में आँकड़े किसी कारण से पर्याप्त वर्तमान नहीं हैं। उदाहरण के लिए:
- नहीं
autovacuum
चल रहा है। - एक बड़े
INSERT
. के तुरंत बाद /UPDATE
/DELETE
। TEMPORARY
टेबल (जोautovacuum
. द्वारा कवर नहीं हैं )।
यह केवल एक यादृच्छिक n . को देखता है % (1
उदाहरण में) ब्लॉकों का चयन और उसमें पंक्तियों की गणना करना। एक बड़ा नमूना लागत बढ़ाता है और त्रुटि को कम करता है, आपकी पसंद। सटीकता अधिक कारकों पर निर्भर करती है:
- पंक्ति आकार का वितरण। यदि दिया गया ब्लॉक सामान्य पंक्तियों से अधिक चौड़ा होता है, तो गिनती सामान्य से कम होती है आदि।
- मृत टुपल्स या एक
FILLFACTOR
प्रति ब्लॉक स्थान पर कब्जा। यदि तालिका में असमान रूप से वितरित किया जाता है, तो अनुमान बंद हो सकता है। - सामान्य गोलाई त्रुटियाँ।
आमतौर पर, pg_class
. से अनुमान तेज़ और अधिक सटीक होगा।
वास्तविक प्रश्न का उत्तर
<ब्लॉकक्वॉट>सबसे पहले, मुझे उस तालिका में पंक्तियों की संख्या जानने की आवश्यकता है, यदि कुल संख्या कुछ पूर्वनिर्धारित स्थिरांक से अधिक है,
और चाहे वो...
<ब्लॉकक्वॉट>... इस समय संभव है कि गिनती मेरे स्थिर मान को पार कर जाए, यह गिनती को रोक देगा (और यह सूचित करने के लिए गिनती समाप्त करने की प्रतीक्षा नहीं करेगा कि पंक्ति की संख्या अधिक है)।
हां। आप सबक्वायरी का उपयोग LIMIT
के साथ कर सकते हैं :
SELECT count(*) FROM (SELECT 1 FROM token LIMIT 500000) t;
पोस्टग्रेज वास्तव में गिनना बंद कर देता है दी गई सीमा से परे, आपको सटीक और वर्तमान मिलता है n . तक गिनें पंक्तियाँ (उदाहरण में 500000), और n अन्यथा। pg_class
. में अनुमान जितना तेज़ नहीं है , हालांकि।