查询性能缓慢的原因是什么?

时间:2012-09-18 06:58:28

标签: mysql performance-testing

我正在阅读最大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
    )
)

2 个答案:

答案 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表明它确实在这种情况下扫描了表格。