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

mmd*_*bas 3 mysql performance-testing

我正在阅读tick最大的记录值id.导致执行缓慢的以下查询之间有什么区别?

慢查询:

SELECT tick
FROM   eventlog
WHERE  id IN (SELECT max(id) FROM eventlog)
Run Code Online (Sandbox Code Playgroud)

快速查询:

SELECT max(id) INTO @id
FROM   eventlog;

SELECT tick
FROM   eventlog
WHERE  id = @id;
Run Code Online (Sandbox Code Playgroud)

架构

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
    )
)
Run Code Online (Sandbox Code Playgroud)

Woj*_*usJ 5

试着看一下查询计划,在这种情况下DBMS可能无法使用索引.尝试将查询更改为:

SELECT tick
FROM   eventlog
WHERE  id = (SELECT max(id) FROM eventlog)
Run Code Online (Sandbox Code Playgroud)

编辑 实际上可能有更好的方法.在上面的查询中,您执行两个INDEX ACCESS操作(如果索引不唯一,则执行一个INDEX RANGE SCAN)和一个TABLE ACCESS.相反,你可以这样做:

SELECT tick
FROM   eventlog
ORDER BY id DESC
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

有了这个,应该有一个INDEX ACCESS和一个TABLE ACCESS.实际上,可能存在相当小的差异,因为TABLE ACCESS显然是更昂贵的操作,因此可能会看到差异在大数据集上.


Mar*_*cus 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)
Run Code Online (Sandbox Code Playgroud)

然后我尝试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)
Run Code Online (Sandbox Code Playgroud)

我不知道mysql是否会在可能的情况下将IN查询转换为ORs一个(例如,序列在查询之前已知),并且我没有找到相关文档,但是explain在这种情况下它确实扫描了表格.