2012-04-20 9 views
6

हटाना मैं लगभग 40 मिलियन में से 267 रिकॉर्ड हटाने की कोशिश कर रहा हूं। क्वेरी इस तरह दिखती है:"ताले की कुल संख्या लॉक टेबल आकार से अधिक है" 267 रिकॉर्ड्स

delete from pricedata 
where 
pricedate > '20120413' 

मूल्य char(8) फ़ील्ड है।

मैं innodb_buffer_pool_size समायोजन के बारे में पता है, लेकिन अगर मैं

select from pricedata 
where 
pricedate > '20120413' 

करते हैं और 267 रिकॉर्ड प्राप्त कर सकते हैं (और कहा कि सभी देखते हैं है), कोई त्रुटि है, क्यों इसे हटा पर गला घोंटना है?

और innodb_buffer_pool_size समायोजित करने पर काम नहीं करता है, तो मुझे क्या करना चाहिए?

+2

आप क्या 'मूल्यवान 'पर एक सूचकांक है? – Quassnoi

+0

मैंने पोस्टिंग के तुरंत बाद (और आपकी प्रतिक्रिया से पहले, दुर्भाग्य से) एक को रखा। यह अभी भी इमारत है! अच्छी बात यह सप्ताहांत है ... – davej

उत्तर

2

क्या काम किया: innodb_buffer_pool_size को 256M में बदलना (Quassnoi की मूल टिप्पणी के तहत टिप्पणियां देखें)।

7

ऐसा लगता है कि आपके पास pricedate पर कोई अनुक्रमणिका नहीं है (या MySQL किसी कारण से इस अनुक्रमणिका का उपयोग नहीं करता है)। पर रिकॉर्ड पढ़ सकते हैं और क्वेरी द्वारा फ़िल्टर

REPEATABLE READ (डिफ़ॉल्ट लेनदेन अलगाव स्तर) के साथ

, InnoDB स्थानों ताले साझा किया और ऐसा लगता है आप 40M ताले के लिए पर्याप्त जगह नहीं है।

इस समस्या को हल करने के लिए इन समाधानों में से किसी का उपयोग:

  1. pricedate पर सूचकांक बनाएं अगर यह वहाँ नहीं है (समय लग सकता है)

  2. छोटे टुकड़ों में आपकी क्वेरी तोड़:

    DELETE 
    FROM pricedata 
    WHERE pricedate > '20120413' 
         AND id BETWEEN 1 AND 1000000 
    
    DELETE 
    FROM pricedata 
    WHERE pricedate > '20120413' 
         AND id BETWEEN 1000001 AND 2000000 
    

    आदि (id आवश्यकतानुसार श्रेणियां बदलें)। ध्यान दें कि प्रत्येक कथन को अपने लेन-देन में चलाया जाना चाहिए (यदि AUTOCOMMIT बंद है तो प्रत्येक कथन के बाद प्रतिबद्ध होना न भूलें)।

  3. DELETEREAD COMMITTED लेनदेन अलगाव स्तर के साथ क्वेरी चलाएं। यह InnoDB रिकॉर्ड से लिफ्ट लॉक को जल्द ही पढ़ेगा। यह काम नहीं करेगा यदि आप बाइनरी लॉग इन कथन मोड का उपयोग कर रहे हैं और binlog-unsafe क्वेरी (यह डिफ़ॉल्ट सेटिंग है) की अनुमति न दें।

+0

बढ़िया, धन्यवाद। मैं कोशिश करूँगा और रिपोर्ट करूंगा। – davej

+0

@ डेवज: उस आकार की एक तालिका पर इसमें कम से कम '40' मिनट लगेंगे, और यदि आपके पास बहुत सारे कॉलम (या लंबे 'टेक्स्ट' या बाइनरी कॉलम हैं) तो इसमें घंटों और दिन लगते हैं। यदि आप 'InnoDB 1.1' (या प्लगइन) का उपयोग नहीं कर रहे हैं, तो यह और भी अधिक ले जाएगा। – Quassnoi

+0

आपके सूचनात्मक इनपुट के लिए फिर से धन्यवाद। कुल 8 फ़ील्ड हैं; "मूल्यवान", केवल गैर-संख्यात्मक है। वहाँ हैं, थियो, 2 बिगिनट (20), इसलिए मुझे नहीं पता कि इसमें कैसा लगेगा। वैसे भी, मुझे कुछ घंटों तक बाहर जाना होगा, इसलिए मैं इसे चलाने दूँगा। अच्छी बात यह एक परीक्षण डीबी पर है! – davej

4

innodb_buffer_pool_size को बदलने के लिए हो रही है या एक सूचकांक बनाने के बिना (ए देर जवाब है, लेकिन alwayx अच्छा यह है करने के लिए जब लोग गूगल में इस मुद्दे को खोजने)

एक समाधान पंक्तियों की मात्रा को सीमित करने के लिए किया जा सकता है हटाए जाने के लिए ।

तो, उदाहरण के लिए DELETE from pricedata where pricedata > '20120413' limit 100; आपके मामले में। यह 100 पंक्तियों को हटा देगा और 167 पीछे छोड़ देगा। तो, आप एक ही क्वेरी को फिर से चला सकते हैं और एक और 100 हटा सकते हैं। पिछले 67 के लिए यह मुश्किल है ... जब डेटाबेस में छोड़ी गई पंक्तियों की मात्रा दी गई सीमा से कम है तो आप फिर से संख्या के बारे में त्रुटि के साथ समाप्त हो जाएंगे ताले के। शायद क्योंकि सर्वर 100 तक भरने के लिए अधिक मिलान पंक्तियों की खोज करेगा। इस मामले में, अंतिम भाग को हटाने के लिए limit 67 का उपयोग करें। (बेशक आप limit 267 पहले से ही के रूप में अच्छी शुरुआत में इस्तेमाल कर सकते हैं)

और कौन स्क्रिप्ट चाहते उन ... एक अच्छा उदाहरण मैं सफाई पुराने डेटा के लिए एक bash स्क्रिप्ट में प्रयोग किया के लिए:

# Count the number of rows left to be deleted 
    QUERY="select count(*) from pricedata where pricedata > '20120413';" 
    AMOUNT=`${MYSQL} -u ${MYSQL_USER} -p${MYSQL_PWD} -e "${QUERY}" ${DB} | tail -1` 
    ERROR=0 
    while [ ${AMOUNT} -gt 0 -a ${ERROR} -eq 0 ] 
    do 
     ${LOGGER} " ${AMOUNT} rows left to delete" 
     if [ ${AMOUNT} -lt 1000 ] 
     then 
     LIMIT=${AMOUNT} 
     else 
     LIMIT=1000 
     fi 
     QUERY="delete low_priority from pricedata where pricedata > '20120413' limit ${LIMIT};" 
     ${MYSQL} -u ${MYSQL_USER} -p${MYSQL_PWD} -e "${QUERY}" ${DB} 
     STATUS=$? 
     if [ ${STATUS} -ne 0 ] 
     then 
     ${LOGGER} "Cleanup failed for ${TABLE}" 
     ERROR=1 
     fi 
     QUERY="select count(*) from pricedata where pricedata > '20120413';" 
     AMOUNT=`${MYSQL} -u ${MYSQL_USER} -p${MYSQL_PWD} -e "${QUERY}" ${DB} | tail -1` 
    done 
संबंधित मुद्दे