2011-09-09 17 views
6

Truy vấn mysql này chạy trong khoảng 10 giờ và chưa hoàn thành. Một cái gì đó khủng khiếp sai.Xóa rất chậm trên cơ sở mysql với truy vấn phụ

Hai bảng (văn bản và spam) có tại đây. Spam lưu trữ các id của các mục nhập spam trong văn bản mà tôi muốn xóa.

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

spam chỉ có 2 cột, cả hai đều là int. Mục nhập 800K có kích thước tệp là vài Mbs. Cả hai ints là khóa chính.

văn bản có 3 cột. id (khóa chính), văn bản, cờ. khoảng 1200K mục và kích thước khoảng 2,1 gigabyte (phần lớn là spam).

Máy chủ là một quad xeon, ram 2 gigabyte (không hỏi tôi tại sao). Chỉ apache (tại sao?) Và mysqld đang chạy. Một bsd miễn phí cũ của nó và mysql 4.1.2 (không hỏi tôi tại sao)

Chủ đề: 6 Câu hỏi: 188805 Truy vấn chậm: 318 Mở: 810 Bàn tuôn ra: 1 Bảng mở: 157 Truy vấn trên giây: 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 

các truy vấn được sử dụng chỉ là một CPU, top nói 25% thời gian CPU (do 1 trong tổng số 4).

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 

Bạn có ý tưởng khắc phục sự cố không?

+0

các công cụ lưu trữ trên bàn là gì? – JamesHalsall

+0

Truy vấn của bạn bao gồm cột old_id, nhưng mô tả của bạn về bảng 'văn bản' không - có thực sự mô tả toàn bộ bảng không? Nói chung, tôi nghi ngờ vấn đề này sẽ kỳ diệu biến mất với một phiên bản MySQL mới hơn. –

+1

Đảm bảo bạn có chỉ mục trên 'text.old_id' và' spam.textid'. – Johan

Trả lời

11

Trong truy vấn phụ kinh nghiệm của tôi thường là nguyên nhân của thời gian thực hiện chậm trong câu lệnh SQL, do đó tôi cố gắng tránh chúng. Hãy thử điều này:

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

Tuyên bố từ chối: Truy vấn này không được kiểm tra, tạo bản sao lưu trước! :-)

+0

-1 vì sử dụng cú pháp SQL ẩn, thoát ra khỏi năm 1989 và sử dụng các phép nối tường minh để thay thế. Ngoài ra điều này sẽ không giải quyết được vấn đề như khẳng định của bạn là không đúng sự thật. OP cần đưa chỉ mục vào các lĩnh vực liên quan đến việc tham gia. – Johan

+0

Xác nhận của ông rất đúng cho các phiên bản MySQL của cổ điển đó. Khi họ lần đầu tiên giới thiệu các truy vấn phụ, và trong một thời gian sau đó, có rất nhiều vấn đề về hiệu suất với chúng. –

+0

+1, cũng đảm bảo bạn có chỉ mục trên spam.textid. – nobody

1

Sao chép các hàng không ở dạng spam dưới dạng text sang bảng mới. Sau đó xóa bảng text và đổi tên bảng đã tạo. Ý tưởng hay không là thêm bất kỳ khóa nào vào bảng đã tạo. Thêm khóa sau khi đổi tên.

+0

Nghiêm túc ??? ..... – Antoniossss

+0

Có thực sự nghiêm túc! Tại sao tôi không nghĩ về điều đó, giải pháp tốt nhất ở đây trong hầu hết các ứng dụng thực tế cho đến nay! – taur

5

Lựa chọn của bạn là where id in (select ...) sẽ luôn hoạt động kém.

Thay vào đó, sử dụng một bình thường tham gia mà sẽ rất hiệu quả: lựa chọn

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

Thông báo từ thư rác đầu tiên, sau đó tham gia vào văn bản, mà sẽ cung cấp hiệu suất tốt nhất.

0

của Corse nó sẽ mất rất nhiều thời gian bởi vì nó thực hiện subquery cho mỗi kỷ lục nhưng bằng cách sử dụng INNER JOIN trực tiếp truy vấn này được thực hiện một lần duy nhất cho phép nghĩ rằng các truy vấn sẽ mất

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

nhưng sử dụng tham gia truy vấn sẽ chỉ được thực hiện một lần:

DELETE t FROM tname.text t INNER JOIN (SELECT textid FROM spam) sq on t.old_id = sq.textid ;