我正在阅读最大tick
的记录的id
值。导致执行缓慢的以下查询之间有什么区别?
SELECT tick
FROM eventlog
WHERE id IN (SELECT max(id) FROM eventlog)
SELECT max(id) INTO @id
FROM eventlog;
SELECT tick
FROM eventlog
WHERE id = @id;
CREATE TABLE eventlog (
id INT (11) NOT NULL AUTO_INCREMENT,
tick INT NOT NULL,
eventType_id INT NOT NULL,
compType INT (10) UNSIGNED NOT NULL,
compID INT (10) UNSIGNED NOT NULL,
value_double DOUBLE NOT NULL,
value_int INT (10),
hierarchy_id VARCHAR (255) NOT NULL,
PRIMARY KEY (id),
INDEX htet (
hierarchy_id,
tick,
eventType_id
)
)
答案 0 :(得分:5)
尝试查看查询计划,在这种情况下DBMS可能无法使用索引。尝试将查询更改为:
SELECT tick
FROM eventlog
WHERE id = (SELECT max(id) FROM eventlog)
修改强> 实际上可能有更好的方法。在上面的查询中,您执行两个INDEX ACCESS操作(如果索引不唯一,则执行一个INDEX RANGE SCAN)和一个TABLE ACCESS。相反,你可以这样做:
SELECT tick
FROM eventlog
ORDER BY id DESC
LIMIT 1
有了这个,应该有一个INDEX ACCESS和一个TABLE ACCESS。实际上,可能存在相当小的差异,因为TABLE ACCESS显然是更昂贵的操作,因此可能会看到差异在大数据集上。
答案 1 :(得分:5)
因为in
查询不使用索引,所以mysql将扫描所有记录以找到该行。
来自http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
B树索引特征
B树索引可用于表达式中的列比较 使用=,>,> =,<,< =或BETWEEN运算符。
没有IN
并且
哈希指数特征
哈希索引的特征与刚才讨论的有些不同:
它们仅用于使用=或< =>的等式比较。 运营商(但速度很快)。它们不用于比较 运营商如<找到一系列价值观。
也没有IN
。
正如@tombom所说,foo IN ('bar', 'bla')
是foo = 'bar' OR foo = 'bla'
的缩写,不过,我相信它们是不同的。因此,我在具有足够数据记录的表上进行测试,并找出以下内容:
mysql> show columns from t_key;
+-------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+----------------+
| a | int(11) | NO | PRI | NULL | auto_increment |
| b | int(11) | YES | MUL | NULL | |
+-------+---------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> select count(a) from t_key;
+----------+
| count(a) |
+----------+
| 989901 |
+----------+
1 row in set (0.00 sec)
mysql> explain select a from t_key where a in (select max(a) from t_key);
+----+--------------------+-------+-------+---------------+---------+---------+------+--------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+---------------+---------+---------+------+--------+------------------------------+
| 1 | PRIMARY | t_key | index | NULL | PRIMARY | 4 | NULL | 989901 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+--------------------+-------+-------+---------------+---------+---------+------+--------+------------------------------+
2 rows in set (0.00 sec)
mysql> explain select a from t_key where a =(select max(a) from t_key);
+----+-------------+-------+-------+---------------+---------+---------+-------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+------------------------------+
| 1 | PRIMARY | t_key | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index |
| 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+------------------------------+
2 rows in set (0.00 sec)
然后我尝试使用静态序列进行IN
查询,它可以像@tombom一样提到:
mysql> explain select a from t_key where a in (100,200);
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| 1 | SIMPLE | t_key | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
mysql> explain select a from t_key where a=100 or a=200;
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
| 1 | SIMPLE | t_key | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where; Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
我不知道mysql是否会在可能的情况下将IN
查询转换为ORs
一个(例如,在查询之前知道序列),并且我没有找到相关文档,但是explain
表明它确实在这种情况下扫描了表格。