2011-09-09 14 views
6

このmysqlクエリは約10時間実行されており、終了していません。何かがひどく間違っています。サブクエリを持つmysqlベースで非常に遅い削除

2つのテーブル(テキストとスパム)がここにあります。スパムは、削除するテキストに迷惑メールエントリのIDを格納します。

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

スパムは2つの列しかなく、どちらもintです。 800Kエントリのファイルサイズは数MBです。どちらのintも主キーです。

テキストには3つの列があります。 id(プリム・キー)、text、flags約1200Kエントリ、およそ2.1ギガバイトのサイズ(ほとんどのスパム)。

サーバーはxeon quad、2ギガバイトのラムです(なぜ私に質問しないでください)。 Apache(なぜ?)とmysqldだけが動いています。それは古い無料のbsdと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 

クエリは、単に1つのCPUを使用して、トップは(SO 1〜4の)25%のCPU時間を言います。

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

あなたのクエリにはold_idカラムが含まれていますが、テーブル 'text'の説明はありません。全体的に、私はこの問題が新しい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のセキュリティ修正が必要ですが、1989年を抜けて明示的な結合を代わりに使用するためのいくつかのバックポートがあります。あなたの主張が真実でないとしても、これは問題を解決しません。 OPは、結合に関与するフィールドにインデックスを配置する必要があります。 – Johan

+0

彼の主張は、そのヴィンテージのMySQL版にも非常に当てはまります。最初にサブクエリを導入した後、しばらくの間、パフォーマンスに関する問題が多発しました。 –

+0

+1また、spam.textidにインデックスがあることを確認してください。 – nobody

1

spamにない行をtextに新しい表にコピーします。テーブルtextを削除し、作成したテーブルの名前を変更します。 作成したテーブルにキーを追加しないことをお勧めします。名前を変更した後にキーを追加します。

+0

真剣に..... ..... – Antoniossss

+0

はい、真剣に!なぜ私はこれを考えていませんでした。ここで最も実用的なアプリケーションでは最高のソリューションです。 – taur

5

あなたが選択したwhere id in (select ...)は、常にパフォーマンスが低くなります。そして、最高のパフォーマンスを与えるであろう、テキストに入社、最初のスパムから

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

お知らせの選択:

代わりに、通常は非常に効率的になるの参加を使用しています。コルスの

0

それはすべてのレコードに対してサブクエリを実行するために多くの時間がかかるが、INNERを使用します。このクエリが実行された直接のJOINのみ1時間 は、クエリが

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

しかしを取ることを考えることができますjoinを使用すると、クエリは1回だけ実行されます。

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