DELETE कमांड 30,000,000 पंक्ति तालिका पर पूरी नहीं होती है


22

मुझे एक डेटाबेस विरासत में मिला है और मैं इसे साफ और गति देना चाहता हूं। मेरे पास एक मेज है जिसमें 30,000,000 पंक्तियाँ हैं, जिनमें से कई हमारे प्रोग्रामर की ओर से त्रुटि के कारण रद्दी डेटा डाली गई हैं। इससे पहले कि मैं कोई नया, अधिक अनुकूलित अनुक्रमणिका जोड़ूं, मैंने तालिका को MyISAM से InnoDB में बदल दिया और बहुत सारी पंक्तियों को हटाने के लिए देख रहा हूं जिनमें जंक डेटा शामिल है।

डेटाबेस MySQL 5.0 है और मेरे पास सर्वर तक रूट एक्सेस है। मैं पहले इन कमांड को प्रशासक और फिर phpMyAdmin के माध्यम से चला रहा था, दोनों एक ही परिणाम के साथ।

मैं जो कमांड चला रहा हूं वह है,

DELETE
FROM `tablename`
WHERE `columnname` LIKE '-%'

अनिवार्य रूप से, डैश से शुरू होने वाले इस कॉलम में कुछ भी हटाएं -

यह लगभग 3-5 मिनट तक चलता है और फिर जब मैं प्रक्रिया सूची देखता हूं, तो यह चला गया है।

मैं तो चला,

SELECT *
FROM `tablename`
WHERE `columnname` LIKE '-%'

और यह लाखों पंक्तियों को लौटाता है।

मेरा डिलीट स्टेटमेंट पूरा क्यों नहीं हो रहा है?

पुनश्च, मुझे पता है कि MySQL 5.0 कितना पुराना है। मैं DB को MySQL 5.6 w InnoDB (शायद MariaDB 10 w XtraDB) पर ले जाने पर काम कर रहा हूं, लेकिन जब तक ऐसा नहीं होता, तब तक मैं DB के साथ इसका उत्तर देना चाहता हूं।

-

संपादित संपादित करें, मेरा उत्तर देखें।

जवाबों:


24

कृपया इनोओडीबी के आर्किटेक्चर को देखें (पेरकोना सीटीओ वादिम टाकेंको से तस्वीर)

InnoDB नलसाजी

आपके द्वारा हटाई जा रही पंक्तियों को पूर्ववत लॉग में लिखा जा रहा है। डिलीट की अवधि के लिए फ़ाइल ibdata1 अभी बढ़ रही होनी चाहिए। Mysqlperformanceblog.com केReasons for run-away main Innodb Tablespace अनुसार :

  • लेन-देन परिवर्तन के बहुत सारे
  • बहुत लंबे लेन-देन
  • लगेज पर्ज धागा

आपके मामले में, कारण # 1 पंक्तियों को हटाने के बाद से कुछ पूर्ववत स्थान के साथ एक रोलबैक खंड पर कब्जा कर लेंगे। उन पंक्तियों को ibdata1 में तब तक बैठना चाहिए जब तक कि डिलीट समाप्त न हो जाए। वह स्थान तार्किक रूप से त्याग दिया गया है लेकिन डिस्कस्पेस वापस सिकुड़ता नहीं है।

आपको उस किल को मारने की आवश्यकता है जो अभी है। एक बार जब आप डिलीट क्वेरी को मार देते हैं, तो यह डिलीट हुई पंक्तियों को रोलबैक कर देगा।

आप इसके बजाय ऐसा करें:

CREATE TABLE tablename_new LIKE tablename;
INSERT INTO tablename_new SELECT * FROM tablename WHERE `columnname` NOT LIKE '-%';
RENAME TABLE
    tablename TO tablename_old,
    tablename_new TO tablename
;
DROP TABLE tablename_old;

आप पहले तालिका के MyISAM संस्करण के खिलाफ ऐसा कर सकते थे। फिर, इसे InnoDB में कनवर्ट करें।


21

मुझे लगता है कि हमने उस उत्तर को पूरा कर लिया है जो मेरे मामले में आवश्यक था । मुझे कोई संदेह नहीं है कि रोलाण्ड और रिक जेम्स दोनों एक अस्थायी टेबल के निर्माण के साथ सही हैं, केवल पंक्तियों को इंजेक्ट करते हुए जो फ़िल्टर को पार करते हैं NOT LIKE '-%'लेकिन मेरे लिए समाधान "आसान" था क्योंकि एक महत्वपूर्ण त्रुटि थी जिससे मैं अब तक और उसके लिए अनजान था। कि मैं माफी मांगता हूं।

मैंने mysqlइंटरएक्टिव प्रॉम्प्ट में क्वेरी को चलाया और त्रुटि संदेश देखा,

mysql> DELETE FROM `slugs` WHERE `slug` LIKE '-%';
ERROR 1206 (HY000): The total number of locks exceeds the lock table size

त्रुटि Googleing के माध्यम से, मैंने पाया कि समाधान फ़ाइल के innodb_buffer_pool_sizeमाध्यम से बढ़ाना था /etc/my.cnfऔर mysql डेमन को रिबूट करना था। मेरे सर्वर के लिए इसे डिफ़ॉल्ट पर सेट किया गया था 8Mऔर मैंने इसे बढ़ा दिया 1G(सर्वर में 32 जीबी है और यह एकमात्र तालिका है जो वर्तमान में इनबीडीबी है)।

mysql> DELETE FROM `slugs` WHERE `slug` LIKE '-%';
Query OK, 23517226 rows affected (27 min 33.23 sec)

तब मैं कमांड चलाने में सक्षम था और ~ 27 मिनट में 23 मिलियन रिकॉर्ड हटा सकता था।

उन उत्सुक लोगों के लिए जो innodb_buffer_pool_sizeसेट होने चाहिए, इस बात पर ध्यान दें कि आपके पास कितनी रैम है और फिर इस धागे पर एक नज़र डालें जो जीबी में सुझाए गए अनुमान देता है।


12

रोलांड के सुझाव को दोनों चीजों को एक बार में पूरा करके देखा जा सकता है:

CREATE TABLE tablename_new LIKE tablename;
ALTER TABLE tablename_new ENGINE = InnoDB;
INSERT INTO tablename_new 
    SELECT * FROM tablename WHERE `columnname` NOT LIKE '-%' ORDER BY primary_key;
RENAME TABLE
    tablename TO tablename_old,
    tablename_new TO tablename
;
DROP TABLE tablename_old;

लेकिन यहाँ एक ब्लॉग है जो यह बताता है कि बड़े-बड़े DELETE कैसे करें, क्योंकि यह हमेशा के लिए लगता है: http://mysql.rjweb.org/doc.php/deletebig , केवल 1K कर के टेबल के माध्यम से चलना है : http://mysql.rjweb.org/doc.php/deletebig एक ही बार में पंक्तियाँ। (निश्चित रूप से इसके बारे में पता करने के लिए अधिक विवरण हैं।)

और यह ब्लॉग InnoDB में रूपांतरण में संभावित गोचरों को संबोधित करता है: http://mysql.rjweb.org/doc.php/myisam2innodb


5

मेरी पहली वृत्ति क्वेरी परिणामों की संख्या को सीमित करके और कई बार क्वेरी को चलाकर एकाधिक, छोटे विलोपन करने की होगी:

DELETE
FROM `tablename`
WHERE `columnname` LIKE '-%' LIMIT 1000000

इस दृष्टिकोण का एक दोष: प्रत्येक हटाने में अधिक समय लगेगा। ऐसा इसलिए है क्योंकि इसे अधिक से अधिक पंक्तियों को छोड़ना होगा जो मेल नहीं खाते WHERE
रिक जेम्स

यह सच है, लेकिन यदि यह प्रक्रिया बहुत बार नहीं हो रही है, तो कई पूर्ण तालिका स्कैन मूल समस्या के हल के रूप में खराब नहीं होनी चाहिए, जो यह है कि क्वेरी पूर्ववत लॉग आकार के कारण कभी भी पूरी नहीं होती है।
kristianp

वैध बिंदु। (मैं LIMITनिम्न करूँगा ; 10000 बोलो।)
रिक जेम्स

4

सबसे आसान उपाय यह है कि बस ऐसा न करें - एक छोटा सा डिलीट करें, जिसे अधिक आसानी से संसाधित किया जा सकता है।

इस मामले में मैंने फॉर्म के क्रमिक विलोपन की कोशिश करने की सिफारिश की है:

DELETE
FROM `tablename`
WHERE `columnname` LIKE '-a%'

2

शायद आप ऐसा कुछ कर सकते हैं:

  • नामक एक नया फ़ील्ड जोड़ें deleted
  • जैसे कोई अपडेट करें UPDATE tablename SET deleted=1 WHERE `columnname` LIKE '-a%'
  • cronरात के समय में इसे हटाने के लिए सेट करें ।

अद्यतन को हटाने में लंबा समय लग सकता है
रिक जेम्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.