1

2 つのデータベース テーブル間で更新クエリを実行していますが、非常に遅いです。例:クエリを実行するには30かかります。

1 つのテーブル lab.list には約 940,000 レコードが含まれ、もう 1 つのテーブルには約 3,700,000 (370 万) の mind.list が含まれます。2 つの BETWEEN 条件が満たされた場合、更新によってフィールドが設定されます。これはクエリです:

UPDATE lab.list L , mind.list M SET L.locId = M.locId  WHERE L.longip BETWEEN M.startIpNum AND M.endIpNum AND L.date BETWEEN "20100301" AND "20100401" AND L.locId = 0

現在、クエリは 8 秒ごとに約 1 回の更新で実行されています。

同じデータベースの mind.list テーブルでも試してみましたが、クエリ時間は問題ありません。

UPDATE lab.list L, lab.mind M  SET L.locId = M.locId  WHERE  longip BETWEEN M.startIpNum AND M.endIpNum AND date BETWEEN "20100301" AND "20100401" AND L.locId = 0;

このクエリを高速化する方法はありますか? 基本的に私見では、データベースの 2 つのサブセットを作成する必要があります: mind.list.longip BETWEEN M.startIpNum AND M.endIpNum lab.list.date BETWEEN "20100301" AND "20100401"

次に、これらのサブセットの値を更新します。どこかで間違いを犯したと思いますが、どこで?たぶん、より高速なクエリが可能ですか?

log_slow_queries を試してみましたが、実際には何億行も調べていることがわかり、おそらく 3331 ギガ行にまで増加しています。

技術情報:

  • サーバーのバージョン: 5.5.22-0ubuntu1-log (Ubuntu)
  • lab.list には locId、longip、date のインデックスがあります
  • lab.mind には、locId、startIpNum、M.endIpNum のインデックスがあります。
  • ハードウェア: 2x xeon 3.4 GHz、4GB RAM、128 GB SSD (問題ないはずです!)
4

2 に答える 2

1

まず、startIpNum、endIpNum、locId の順にインデックスを作成します。locId は、たとえ更新に使用されたとしても、SELECTing from mind では使用されません。

同じ理由で、locId、date、および longip (date で実行する必要がある最初のチャンクでは使用されません) で lab のインデックスを作成します。

では、startIpNum と endIpNum にはどのようなデータ型が割り当てられているのでしょうか。IPv4 の場合は、INTEGER に変換し、ユーザー I/O に INET_ATON と INET_NTOA を使用するのが最適です。あなたはすでにこれを行っていると思います。

更新を実行するには、一時テーブルを使用して M データベースをセグメント化してみてください。あれは:

* select all records of lab in the given range of dates with locId = 0 into a temporary table TABLE1.
* run an analysis on TABLE1 grouping IP addresses by their first N bits (using AND with a suitable mask: 0x80000000, 0xC0000000, ... 0xF8000000... and so on, until you find  that you have divided into a "suitable" number of IP "families". These will, by and large, match with startIpNum (but that's not strictly necessary).
* say that you have divided in 1000 families of IP.
* For each family:
*    select those IPs from TABLE1 to TABLE3.
*    select the IPs matching that family from mind to TABLE2.
*    run the update of the matching records between TABLE3 and TABLE2. This should take place in about one hundred thousandth of the time of the big query.
*    copy-update TABLE3 into lab, discard TABLE3 and TABLE2.
* Repeat with next "family".

これはあまり理想的ではありませんが、わずかに改善されたインデックス作成が役に立たない場合、それほど多くのオプションはありません。

于 2012-07-01T22:28:08.013 に答える
0

結局、クエリはmysqlが満たすには大きすぎるか面倒でした。インデックスを作成した後でも。ハイエンドのSybaseサーバーで同じデータを使用して同じクエリをテストするのにも3時間かかりました。

そこで、データベースサーバーの考えですべてを行うことをやめ、スクリプト言語に戻りました。

Pythonで次のことを行いました。

  1. 370万レコードの100000レコードのチャンクをロードし、行をループします
  2. 行ごとに、locIdを設定し、残りの列に入力します

これらの更新はすべて合わせて約5分かかるため、大幅に改善されます。

結論:

データベースボックスの外側を考えてください!

于 2012-07-10T11:29:52.950 に答える