2013-03-17 10 views
15

もし私が1の代わりに、5MySQLの:劇的に遅いクエリ実行使用LIMIT 1の代わりに、LIMIT 5

SELECT he. * 
FROM homematic_events he 
WHERE he.homematic_devices_id =30 
ORDER BY id DESC 
LIMIT 1 

代わりの

SELECT he. * 
FROM homematic_events he 
WHERE he.homematic_devices_id =30 
ORDER BY id DESC 
LIMIT 5 
にクエリを制限した場合に劇的に速度低下に気づきましたこれらは、高速私を、について説明している

CREATE TABLE IF NOT EXISTS `homematic_events` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `homematic_devices_id` int(11) DEFAULT NULL, 
    `address` char(16) COLLATE utf8_unicode_ci NOT NULL, 
    `interface_id` char(16) COLLATE utf8_unicode_ci NOT NULL, 
    `key` char(32) COLLATE utf8_unicode_ci NOT NULL, 
    `value` float(12,2) NOT NULL, 
    `timestamp` datetime NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `timestamp` (`timestamp`), 
    KEY `address` (`address`), 
    KEY `key` (`key`), 
    KEY `homematic_devices_id` (`homematic_devices_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=12637557 ; 

私の表は、次の構造を有する約12,000,000行が含まれていますLIMIT 5用asurment:誰も私にこの動作を説明でき

mysql> EXPLAIN SELECT he. * FROM homematic_events he WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 1; 
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+ 
| id | select_type | table | type | possible_keys  | key  | key_len | ref | rows | Extra  | 
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+ 
| 1 | SIMPLE  | he | index | homematic_devices_id | PRIMARY | 4  | NULL | 3029 | Using where | 
+----+-------------+-------+-------+----------------------+---------+---------+------+------+-------------+ 

starting        0.000010 
checking query cache for query  0.000034 
Opening tables      0.000009 
System lock       0.000004 
Table lock       0.000015 
init         0.000020 
optimizing       0.000008 
statistics       0.000069 
preparing        0.000016 
executing        0.000002 
Sorting result      0.000005 
Sending data      502.290180 
end         0.000010 
query end        0.000003 
freeing items       0.000293 
logging slow query     0.000004 
logging slow query     0.000002 
cleaning up       0.000003 

ください

mysql> EXPLAIN SELECT he. * FROM homematic_events he WHERE he.homematic_devices_id =30 ORDER BY id DESC LIMIT 5; 
    +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+ 
    | id | select_type | table | type | possible_keys  | key     | key_len | ref | rows | Extra      | 
    +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+ 
    | 1 | SIMPLE  | he | ref | homematic_devices_id | homematic_devices_id | 5  | const | 4171 | Using where; Using filesort | 
    +----+-------------+-------+------+----------------------+----------------------+---------+-------+------+-----------------------------+ 


starting       0.000010 
checking query cache for query 0.000030 
Opening tables     0.000007 
System lock      0.000004 
Table lock      0.000015 
init        0.000019 
optimizing      0.000007 
statistics      0.000098 
preparing       0.000012 
executing       0.000002 
Sorting result     0.022965 
Sending data      0.000047 
end        0.000004 
query end       0.000002 
freeing items      0.000302 
storing result in query cache  0.000009 
logging slow query    0.000002 
cleaning up      0.000003 

これらは、LIMIT 1の速度measurmentを、について説明していますか?私はそれがLIMIT 1のudesである異なるインデックスの結果だと言います。しかし、なぜLIMITの値ごとに異なるキーを使うのですか?

+0

To明らかに、問合せがLIMIT 1よりLIMIT 5より**長く**かかると言っていますか? –

+0

thats right - 約2万倍長くこの場合;-) – Stephan

答えて

3

何らかの理由で、MySQLが主キーIDをインデックスの代わりにこれらの行にアクセスするのに何とか速くなります。あなたが具体的に使用したクエリでは、homematic_devices_idのインデックスが作成されたフィールドを使用します。私はまた、2番目のケースのMySQLがの下にあるhomematic_devices_idしか持っていないが、代わりにPRIMARYを選択するのが奇妙だと分かります。通常、MySQLはPRIMARYと他の可能なインデックスをその列に表示します。

データに依存する問題はありますか?他のdevice_idsでクエリを試しましたか?

どちらの場合もFORCE INDEXを使用して問題を解決できるかどうかを確認してください。

+0

あなたは正しいです。所在地は です。 * からhomematic_events彼FORCE INDEX(homematic_devices_id) WHERE he.homematic_devices_id = 30 ORDER BY id DESC LIMIT 1 うまく動作します!ありがとうございます – Stephan

1

私の仮定は、あなたが持っているとlimit 1と組み合わせるorder byとき、要求が内部的にあなたがlimit 5、発注を求めるときには、インデックスを使用してすぐに到達することができるmax()(または分)として扱われていることです完全に最初に行われなければならない。

8

LIMIT 1では、クエリアナライザがプライマリキーを押し下げて最後のレコードを見つけたとします。homematic_devices_id =30 - おそらくアナライザが「ソート」操作が高価になることを知っているためです。

LIMIT 5では、クエリアナライザが最初にレコードを見つけて並べ替えることにします。その操作を高速化したい場合は、homematic_devices_idとIDの両方にインデックスを作成することができます:ALTER TABLE homematic_events_test ADD INDEX ( homematic_devices_id, id) - 最初にデバイスIDを入れ、Where句に対応し、IDカラムがSORTに役立ちます。

+0

ALTER TABLE 'homematic_events_test' ADD INDEX(' id'、 'homematic_devices_id')? – Stephan

+1

私は答えを更新しました。 –

+0

なぜ限界1は "データの送信中502.290180"を持っていますか?この時点でデータなどが見つかりましたか、これまでに要求した内容に戻します – exussum