2011-09-09 9 views
6

के साथ mysql बेस पर बहुत धीमी गति से हटाएं यह mysql क्वेरी लगभग 10 घंटों तक चल रही है और समाप्त नहीं हुई है। कुछ बहुत गलत है।subquery

दो टेबल (टेक्स्ट और स्पैम) यहां हैं। स्पैम टेक्स्ट में स्पैम एंट्री के आईडी को स्टोर करता है जिसे मैं हटाना चाहता हूं।

DELETE FROM tname.text WHERE old_id IN (SELECT textid FROM spam); 

स्पैम में केवल 2 कॉलम हैं, दोनों इनट हैं। 800K प्रविष्टियों में कई एमबीएस का फ़ाइल आकार है। दोनों स्याही प्राथमिक कुंजी हैं।

टेक्स्ट में 3 कॉलम हैं। आईडी (प्राथमिक कुंजी), पाठ, झंडे। लगभग 1200K प्रविष्टियां, और लगभग 2.1 गीगाबाइट आकार (अधिकतर स्पैम)।

सर्वर एक xeon क्वाड, 2 गीगाबाइट राम है (मुझे क्यों नहीं पूछें)। केवल अपाचे (क्यों?) और mysqld चल रहा है। यह एक पुराना मुफ्त बीएसडी और MySQL 4.1.2 (मुझसे पूछो क्यों नहीं)

धागे: 6 प्रश्न: 188805 धीमे प्रश्न: 318 खुलता है: 810 फ्लश टेबल: 1 ओपन टेबल: 157 क्वेरी प्रति सेकंड औसत: 7.532

Mysql my.cnf:

[mysqld] 
datadir=/usr/local/mysql 
log-error=/usr/local/mysql/mysqld.err 
pid-file=/usr/local/mysql/mysqld.pid 
tmpdir=/var/tmp 
innodb_data_home_dir = 
innodb_log_files_in_group = 2 
join_buffer_size=2M 
key_buffer_size=32M 
max_allowed_packet=1M 
max_connections=800 
myisam_sort_buffer_size=32M 
query_cache_size=8M 
read_buffer_size=2M 
sort_buffer_size=2M 
table_cache=256 
skip-bdb 
log-slow-queries = slow.log 
long_query_time = 1 

#skip-innodb 
#default-table-type=innodb 
innodb_data_file_path = /usr/local/mysql/ibdata1:10M:autoextend 
innodb_log_group_home_dir = /usr/local/mysql/ 
innodb_buffer_pool_size = 128M 
innodb_log_file_size = 16M 
innodb_log_buffer_size = 8M 
#innodb_flush_log_at_trx_commit=1 
#innodb_additional_mem_pool_size=1M 
#innodb_lock_wait_timeout=50 

log-bin 
server-id=201 

[isamchk] 
key_buffer_size=128M 
read_buffer_size=128M 
write_buffer_size=128M 
sort_buffer_size=128M 

[myisamchk] 
key_buffer_size=128M[server:~] dmesg | grep memory 
real memory = 2146828288 (2047 MB) 
avail memory = 2095534080 (1998 MB) 

read_buffer_size=128M 
write_buffer_size=128M 
sort_buffer_size=128M 
tmpdir=/var/tmp 

क्वेरी सिर्फ एक सीपीयू उपयोग कर रहा है, ऊपर का कहना है 25% CPU समय (ताकि 4 में से 1)।

real memory = 2146828288 (2047 MB) 
avail memory = 2095534080 (1998 MB) 

62 processes: 2 running, 60 sleeping 
CPU states: 25.2% user, 0.0% nice, 1.6% system, 0.0% interrupt, 73.2% idle 
Mem: 244M Active, 1430M Inact, 221M Wired, 75M Cache, 112M Buf, 31M Free 
Swap: 4096M Total, 1996K Used, 4094M Free 

    PID USERNAME  THR PRI NICE SIZE RES STATE C TIME WCPU COMMAND 
11536 mysql   27 20 0 239M 224M kserel 3 441:16 94.29% mysqld 

कोई विचार यह कैसे ठीक करें?

+0

टेबल पर स्टोरेज इंजन क्या हैं? – JamesHalsall

+0

आपकी क्वेरी में एक पुराना_आईडी कॉलम शामिल है, लेकिन तालिका 'टेक्स्ट' का आपका विवरण नहीं है - क्या आपने वास्तव में पूरी तालिका का वर्णन किया है? कुल मिलाकर, मुझे संदेह है कि यह समस्या जादुई रूप से एक नए MySQL संस्करण के साथ चलेगी। –

+1

सुनिश्चित करें कि आपके पास 'text.old_id' और' spam.textid' पर अनुक्रमणिका हैं। – Johan

उत्तर

11

मेरे अनुभव में उप प्रश्न अक्सर SQL कथन में धीमे निष्पादन समय का कारण होते हैं, इसलिए मैं उनसे बचने की कोशिश करता हूं। इस प्रयास करें:

DELETE tname FROM tname INNER JOIN spam ON (tname.old_id = spam.textid); 

अस्वीकरण: यह क्वेरी का परीक्षण नहीं किया है, जिसमें पहला बैकअप बनाने! :-)

+0

-1 के लिए सुरक्षा फिक्स को अंतर्निहित SQL वाक्यविन्यास का उपयोग करने के लिए, 1 9 8 9 से बाहर निकलें और इसके बजाय स्पष्ट रूप से शामिल हों। इसके अलावा यह समस्या हल नहीं करेगा क्योंकि आपका दावा असत्य है। ओपी को शामिल होने वाले क्षेत्रों में इंडेक्स डालने की जरूरत है। – Johan

+0

उस विवेक के MySQL संस्करणों के लिए उनका दावा बहुत सच है। जब उन्होंने पहली बार उपक्विरी पेश की, और उसके बाद कुछ समय के लिए, उनके साथ प्रदर्शन के मुद्दों में काफी कुछ था। –

+0

+1, यह भी सुनिश्चित करें कि आपके पास spam.textid पर एक अनुक्रमणिका है। – nobody

1

पंक्तियों की प्रतिलिपि बनाएँ जो spamtext में नई तालिका में नहीं हैं। फिर text तालिका हटाएं और बनाई गई तालिका का नाम बदलें। अच्छा विचार है कि बनाई गई तालिका में कोई भी कुंजी न जोड़ना। नाम बदलने के बाद कुंजी जोड़ें।

+0

गंभीरता से ??? ..... – Antoniossss

+0

हां गंभीरता से! मैंने इसके बारे में क्यों नहीं सोचा, सबसे व्यावहारिक अनुप्रयोगों में अब तक का सबसे अच्छा समाधान! – taur

5

आपकी पसंद where id in (select ...) आपकी पसंद हमेशा खराब होगी।

इसके बजाय, में शामिल होने के जो बहुत ही कुशल हो जाएगा एक सामान्य का उपयोग करें: स्पैम से

DELETE `text` 
FROM spam 
join `text` on `text`.old_id = spam.textid; 

सूचना चयन पहले, तो पाठ में है, जो सबसे अच्छा प्रदर्शन दे देंगे में शामिल होने।

0
कोर्स यह बहुत समय ले, क्योंकि यह हर रिकार्ड के लिए सबक्वेरी निष्पादित करेंगे की लेकिन अंदरूनी का उपयोग करके

सीधे शामिल हों इस क्वेरी केवल एक बार निष्पादित किया जाता है की सुविधा देता है लगता है कि क्वेरी लगेगा

10 ms for 50000 rec full time = 50000 * 10 ms ---> 8.333 minutes !! at least don't forget the condition and deleting time ..... 

लेकिन क्वेरी में शामिल होने का उपयोग केवल एक बार निष्पादित किया जाएगा:

DELETE t FROM tname.text t INNER JOIN (SELECT textid FROM spam) sq on t.old_id = sq.textid ; 
संबंधित मुद्दे