2012-03-22 13 views
2

私は140000以上の行を持つテーブルでいくつかのSQLクエリを作成して展開するPerlスクリプトを書いています。MySQL - なぜこれらの2つのクエリでタイムスタンプが異なるパフォーマンスですか?

日付を比較して行を取得したいのですが、1つのSQLクエリを変更するだけで、実行速度が非常に異なることに気付きました。

100 $ SQLクエリを実行している次のテスト結果を見てください。 異なる実行間でスクリプト内で変更される唯一の行は$ sql行です。

私は何度もテストを実行しましたが、私はいつも同じような結果を得ています。だから、キャッシュの問題には関係していないと思います。 (mysqldumpをから取られた)テーブルが作成されたどのよう

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE `host_id` = $host_id 
AND date >= '$date' 
AND TIMESTAMPDIFF(MINUTE , `date`, '$date') <= $interval;"; # VERY SLOW 

time ./data_smoothing.pl 

real 1m28.818s 
user 1m6.516s 
sys  0m0.256s 

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE `host_id` = $host_id 
AND date >= '$date' 
AND (UNIX_TIMESTAMP(`date`) - UNIX_TIMESTAMP('$date')) <= ($interval * 60);"; #SLOW 

$ time ./data_smoothing.pl 

real 0m10.005s 
user 0m0.108s 
sys  0m0.028s 

my $sql = "SELECT `mem_used`, `swap_used`, `mem_total` 
FROM `$config{db}{data_table}` 
WHERE `host_id` = $host_id 
AND (`date` BETWEEN '$date' 
AND DATE_ADD('$date', INTERVAL $interval MINUTE));"; #FAST 

$ time ./data_smoothing.pl 

real 0m0.190s 
user 0m0.084s 
sys  0m0.016s 

CREATE TABLE `data` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `host_id` smallint(6) NOT NULL, 
    `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 
    `mem_total` double(10,3) DEFAULT NULL, 
    `mem_used` double(10,3) DEFAULT NULL, 
    `swap_total` double(10,3) DEFAULT NULL, 
    `swap_used` double(10,3) DEFAULT NULL, 
    `CPU_count` smallint(6) DEFAULT NULL, 
    `load_avg_1` float DEFAULT NULL, 
    `load_avg_5` float DEFAULT NULL, 
    `load_avg_15` float DEFAULT NULL, 
    `uptime` double(10,3) DEFAULT NULL, 
    `cpuIdlingTime` double(10,3) DEFAULT NULL, 
    `rxBytesTotal` bigint(20) DEFAULT NULL, 
    `txBytesTotal` bigint(20) DEFAULT NULL, 
    `rxPacketsTotal` bigint(20) DEFAULT NULL, 
    `txPacketsTotal` bigint(20) DEFAULT NULL, 
    PRIMARY KEY (`id`,`host_id`), 
    KEY `fk_data_hosts` (`host_id`), 
    KEY `date_memtot_hosts` (`date`,`mem_total`,`host_id`), 
    CONSTRAINT `fk_data_hosts` FOREIGN KEY (`host_id`) REFERENCES `hosts` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE=InnoDB AUTO_INCREMENT=145300 DEFAULT CHARSET=utf8; 

答えて

5

最後のものは索引付けに適しているため、最速です。他のものはそうではありません。

テストする前に、列の値で関数を呼び出すとき(または他の何かについても)、インデックスを使用して一致する行をすばやく見つけることはほとんど不可能です。エンジンは基本的にテーブル全体を巡って日付をつかんで数学をやって、そして次にの条件が真であるかどうかをチェックする必要があります。

BETWEEN this_value AND that_valueと言っても、MySQLはまったく何もする必要はありません。インデックスを参照して、範囲の2つのエンドポイントを見つけることができます。これははるかに高速です。

への呼び出しは実行時間にあまり影響しません。なぜなら、MySQLは一般的に変更されない値をキャッシュするほどスマートなので、毎回それらを計算する必要がないからです。

最初の2つの違いの理由は分かりませんでした。おそらくTIMESTAMPDIFFは遅いです。おそらくUNIX_TIMESTAMP('$date')が毎回再計算する必要はないと考えると、おそらく変換と数学はタイムスタンプでははるかに簡単です。しかし、それは本当にちょうど推測です。

+0

私は見て..良い説明をありがとう! –

+1

Vの場合、このタイプのQを助けるために常にEXPLAINを試してください。この場合、クエリエンジンは 'date'の間に' date_memtot_hosts'を使用できますので、(1)のように全テーブルスキャンを行う必要はありません(2)のようにパーツテーブルスキャンを実行します。 * hot *クエリの場合は、テーブルの(host_id、date)に追加のキーを追加して3を試してください。これはシャベルのようなものです。 – TerryE

+0

EXPLAINコマンドについてのヒントがありませんでした。ありがとうございました! –

0

インデックス関連の問題になるようだ、することができますテーブルの作成を投稿する私たちはあなたのインデックスを見ることができますか?

私は<を知っていますが、BETWEENはうまくいきますが、インデックスを使用するとうまくいきません...おそらくBETWEEN句にリストされている最初の日付の恩恵を受けるでしょう。 DATE_ADD内のものは、索引付けの目的では使用されません(関数ブレーク索引以降)。

+0

尋ねられたように余分な情報を追加しました –

+0

私はインデックスを選ぶときに不平等が最適ではないという事実に固執しますが、BETWEENは利益をもたらします。 – Ray

-1

TIMESTAMPDIFFバージョンでは、引数の順序が間違っているようです。肯定的な結果を得るためには、2番目の議論は2つの日付の後半でなければならない。書かれているとおり、TIMESTAMPDIFF(MINUTE、date、 '$ date')< = $ intervalは常に真です。より多くの結果行が返されるので、TIMESTAMPDIFFバージョンのパフォーマンスがUNIX_TIMESTAMPバージョンよりもずっと悪いように見える理由を説明することができます。

関連する問題