मुझे SQL तालिका में एक बड़ी संख्या में एक SELECT COUNT (*) के साथ एक प्रदर्शन समस्या है।SQLite: बड़ी तालिकाओं पर COUNT धीमी
जैसा कि मुझे अभी तक उपयोग करने योग्य उत्तर नहीं मिला है और मैंने कुछ और परीक्षण किया है, मैंने अपने नए निष्कर्षों को शामिल करने के लिए अपना प्रश्न संपादित किया।
2 टेबल है:
CREATE TABLE Table1 (
Key INTEGER NOT NULL,
... several other fields ...,
Status CHAR(1) NOT NULL,
Selection VARCHAR NULL,
CONSTRAINT PK_Table1 PRIMARY KEY (Key ASC))
CREATE Table2 (
Key INTEGER NOT NULL,
Key2 INTEGER NOT NULL,
... a few other fields ...,
CONSTRAINT PK_Table2 PRIMARY KEY (Key ASC, Key2 ASC))
Table1 लगभग 8 मिलियन रिकॉर्ड है और तालिका 2 लगभग 51 मिलियन रिकॉर्ड है, और databasefile 5GB खत्म हो गया है।
CREATE INDEX IDX_Table1_Status ON Table1 (Status ASC, Key ASC)
CREATE INDEX IDX_Table1_Selection ON Table1 (Selection ASC, Key ASC)
"स्थिति" की आवश्यकता है क्षेत्र केवल 6 अलग-अलग मान, "चयन" की आवश्यकता नहीं है, लेकिन है और केवल लगभग 15 लाख मूल्यों बातिल और केवल चारों ओर से अलग है:
Table1 2 अधिक अनुक्रमित है 600k विशिष्ट मूल्य।
मैंने दोनों टेबलों पर कुछ परीक्षण किए हैं, आप नीचे दिए गए समय देख सकते हैं, और मैंने प्रत्येक अनुरोध (क्यूपी) के लिए "क्वेरी प्लान समझाया" जोड़ा। मैंने डेटाबेस फ़ाइल को यूएसबी-मेमोरीस्टिक पर रखा ताकि मैं प्रत्येक टेस्ट के बाद इसे हटा सकूं और डिस्क कैश के हस्तक्षेप के बिना विश्वसनीय परिणाम प्राप्त कर सकूं। यूएसबी पर कुछ अनुरोध तेज हैं (मुझे लगता है कि तलाश समय की कमी के कारण), लेकिन कुछ धीमे (टेबल स्कैन) हैं।
SELECT COUNT(*) FROM Table1
Time: 105 sec
QP: SCAN TABLE Table1 USING COVERING INDEX IDX_Table1_Selection(~1000000 rows)
SELECT COUNT(Key) FROM Table1
Time: 153 sec
QP: SCAN TABLE Table1 (~1000000 rows)
SELECT * FROM Table1 WHERE Key = 5123456
Time: 5 ms
QP: SEARCH TABLE Table1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
SELECT * FROM Table1 WHERE Status = 73 AND Key > 5123456 LIMIT 1
Time: 16 sec
QP: SEARCH TABLE Table1 USING INDEX IDX_Table1_Status (Status=?) (~3 rows)
SELECT * FROM Table1 WHERE Selection = 'SomeValue' AND Key > 5123456 LIMIT 1
Time: 9 ms
QP: SEARCH TABLE Table1 USING INDEX IDX_Table1_Selection (Selection=?) (~3 rows)
आप देख सकते हैं मायने रखता है बहुत धीमी गति से कर रहे हैं, लेकिन सामान्य चयन तेजी से (2 है, जो 16 सेकंड लगे को छोड़कर) कर रहे हैं।
एक ही तालिका 2 के लिए चला जाता है:
SELECT COUNT(*) FROM Table2
Time: 528 sec
QP: SCAN TABLE Table2 USING COVERING INDEX sqlite_autoindex_Table2_1(~1000000 rows)
SELECT COUNT(Key) FROM Table2
Time: 249 sec
QP: SCAN TABLE Table2 (~1000000 rows)
SELECT * FROM Table2 WHERE Key = 5123456 AND Key2 = 0
Time: 7 ms
QP: SEARCH TABLE Table2 USING INDEX sqlite_autoindex_Table2_1 (Key=? AND Key2=?) (~1 rows)
क्यों SQLite Table1 पर प्राथमिक कुंजी पर स्वचालित रूप से बनाया सूचकांक का उपयोग नहीं कर रहा है? और क्यों, जब वह तालिका 2 पर ऑटो-इंडेक्स का उपयोग करता है, तो इसमें अभी भी बहुत समय लगता है?
मैंने SQL Server 2008 R2 पर समान सामग्री और अनुक्रमणिका के साथ एक ही सारणी बनाई और वहां गणना लगभग तात्कालिक हैं।
नीचे दी गई टिप्पणियों में से एक डेटाबेस पर विश्लेषण निष्पादित करने का सुझाव दिया गया है। मैंने किया और इसे पूरा होने में 11 मिनट लग गए। उसके बाद, मैं परीक्षण के कुछ फिर से भाग:
SELECT COUNT(*) FROM Table1
Time: 104 sec
QP: SCAN TABLE Table1 USING COVERING INDEX IDX_Table1_Selection(~7848023 rows)
SELECT COUNT(Key) FROM Table1
Time: 151 sec
QP: SCAN TABLE Table1 (~7848023 rows)
SELECT * FROM Table1 WHERE Status = 73 AND Key > 5123456 LIMIT 1
Time: 5 ms
QP: SEARCH TABLE Table1 USING INTEGER PRIMARY KEY (rowid>?) (~196200 rows)
SELECT COUNT(*) FROM Table2
Time: 529 sec
QP: SCAN TABLE Table2 USING COVERING INDEX sqlite_autoindex_Table2_1(~51152542 rows)
SELECT COUNT(Key) FROM Table2
Time: 249 sec
QP: SCAN TABLE Table2 (~51152542 rows)
आप देख सकते हैं, प्रश्नों एक ही समय लिया (क्वेरी योजना को छोड़कर अब पंक्तियों की वास्तविक संख्या को दिखा रहा है), केवल धीमी चयन है अब भी तेज़
अगला, मैं तालिका 1 के मुख्य क्षेत्र पर डैन अतिरिक्त अनुक्रमणिका बना देता हूं, जो ऑटो-इंडेक्स से मेल खाना चाहिए। मैंने विश्लेषण डेटा के बिना मूल डेटाबेस पर किया था। इस इंडेक्स को बनाने में 23 मिनट लग गए (याद रखें, यह यूएसबी-स्टिक पर है)।
CREATE INDEX IDX_Table1_Key ON Table1 (Key ASC)
तब मैं परीक्षण फिर से भाग:
SELECT COUNT(*) FROM Table1
Time: 4 sec
QP: SCAN TABLE Table1 USING COVERING INDEX IDX_Table1_Key(~1000000 rows)
SELECT COUNT(Key) FROM Table1
Time: 167 sec
QP: SCAN TABLE Table2 (~1000000 rows)
SELECT * FROM Table1 WHERE Status = 73 AND Key > 5123456 LIMIT 1
Time: 17 sec
QP: SEARCH TABLE Table1 USING INDEX IDX_Table1_Status (Status=?) (~3 rows)
आप देख सकते हैं, सूचकांक गिनती (*) से मदद की, लेकिन गिनती (कुंजी) के साथ नहीं।
CREATE TABLE Table1 (
Key INTEGER PRIMARY KEY ASC NOT NULL,
... several other fields ...,
Status CHAR(1) NOT NULL,
Selection VARCHAR NULL)
तब मैं परीक्षण फिर से भाग:
SELECT COUNT(*) FROM Table1
Time: 6 sec
QP: SCAN TABLE Table1 USING COVERING INDEX IDX_Table1_Selection(~1000000 rows)
SELECT COUNT(Key) FROM Table1
Time: 28 sec
QP: SCAN TABLE Table1 (~1000000 rows)
SELECT * FROM Table1 WHERE Status = 73 AND Key > 5123456 LIMIT 1
Time: 10 sec
QP: SEARCH TABLE Table1 USING INDEX IDX_Table1_Status (Status=?) (~3 rows)
हालांकि क्वेरी योजना, एक ही हैं
अंत में, मैं मेज के बजाय एक स्तंभ बाधा का उपयोग कर एक मेज बाधा के बनाया समय बहुत बेहतर हैं। ऐसा क्यों है ?
समस्या यह है कि वैकल्पिक तालिका मौजूदा तालिका को कनवर्ट करने की अनुमति नहीं देती है और मेरे पास बहुत सारे मौजूदा डेटाबेस हैं जिन्हें मैं इस फ़ॉर्म में परिवर्तित नहीं कर सकता। इसके अलावा, टेबल बाधा के बजाय कॉलम contraint का उपयोग तालिका 2 के लिए काम नहीं करेगा।
क्या किसी को कोई विचार है कि मैं क्या गलत कर रहा हूं और इस समस्या को कैसे हल किया जाए?
मैंने टेबल बनाने के लिए System.Data.SQLite संस्करण 1.0.74.0 का उपयोग किया और परीक्षण चलाने के लिए मैंने SQLiteSpy 1.9.1 का उपयोग किया।
धन्यवाद,
मार्क
यदि आपके पास SQLite के साथ प्रदर्शन समस्याएं हैं, तो समाधान आमतौर पर एक बड़े डीबी सर्वर पर जाने के लिए होता है (मैं एमएस एसक्यूएल पर पोस्टग्रेस की अनुशंसा करता हूं)। – Borealid
मुझे कोई अन्य प्रदर्शन समस्या नहीं है, अन्य सभी चयन तेजी से हैं (और सही इंडेक्स का उपयोग करें), आवेषण और अपडेट तेज़ हैं, यह केवल गिनती है जो मुझे परेशान करती है। – Marc
जो वास्तव में डरावना है, क्योंकि (कम से कम डीबी 2 के लिए) अधिकांश आरडीबीएमएस शायद प्रभावी रूप से कैश की गई जानकारी का उपयोग करते हैं - यदि आप _all_ पंक्तियों (या किसी इंडेक्स में किसी चीज़ द्वारा प्रतिबंधित) की गणना के लिए पूछते हैं, तो यह आमतौर पर उस जानकारी को पढ़ सकता है सूचकांक स्वयं - सूचकांक प्रविष्टियों की संख्या जानता है। यह दोगुना डरावना है कि आप कहते हैं कि अन्य सभी 'चयन' तेज़ हैं - उन्हें सही मायने में अनुकूलित करने में सक्षम होने के लिए रिकॉर्ड गणना की आवश्यकता है! जब तक कुछ डरावना नहीं हो रहा है, और आप तालिका को लॉक कर रहे हैं (दोहराने योग्य पढ़ने का लेनदेन स्तर, या कुछ ऐसे?) ... –