mysql,密钥和优化:我的密钥似乎没用吗?

时间:2011-12-24 14:16:54

标签: mysql query-optimization

以下是我已经完成的sql命令,我不明白为什么没有密钥(~1.45 s)和密钥(~1.15 s)之间的区别很小:

mysql> show create table devis;
| devis | CREATE TABLE `devis` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  ...blabla...
  `date_v_creation` datetime default NULL,
  `date_v_fin` datetime default NULL,
  ...blabla...
  `etat` tinyint(4) default NULL,
  `etat_date` datetime default NULL,
  PRIMARY KEY  (`id`),
  KEY `date_v_creation` (`date_v_creation`),
  KEY `date_v_fin` (`date_v_fin`),
  ...blabla...
) ENGINE=InnoDB AUTO_INCREMENT=3714317 DEFAULT CHARSET=utf8 |

mysql> select date_v_creation from devis
where etat=3
and date_v_fin is null
and TO_DAYS(NOW()) - TO_DAYS(date_v_creation) > 54;

+---------------------+
| date_v_creation     |
+---------------------+
| 2011-10-30 21:44:54 | 
| ...blabla...        | 
| 2011-10-30 21:48:05 | 
+---------------------+
216 rows in set (1.45 sec)

mysql> alter table devis add key( date_v_fin, etat);

mysql> select date_v_creation from devis
where etat=3
and date_v_fin is null
and TO_DAYS(NOW()) - TO_DAYS(date_v_creation) > 54;

+---------------------+
| date_v_creation     |
+---------------------+
| 2011-10-30 21:44:54 | 
| ...blabla...        | 
| 2011-10-30 21:48:05 | 
+---------------------+
216 rows in set (1.13 sec)

如果我这么做很多次,它总是介于(1.05秒)和(1.15秒)之间。

很多时候,我添加了密钥以缩短响应时间,当它不起作用时,时间没有改变,当它工作时,时间变为从最低的10倍到

我做错了什么,错过了什么,或者这种正常收益是如此之少?

非常感谢!

更新

这是解决我的问题的查询,但我仍然不知道为什么它解决了它。

select date_v_creation
from devis
where etat=3
  and date_v_creation < NOW() - INTERVAL 54 DAY
  and date_v_fin is null;   

以下是我的“糟糕”查询的解释:

mysql> EXPLAIN select date_v_creation from devis where etat=3 and date_v_fin is null and TO_DAYS(NOW()) - TO_DAYS(date_v_creation) > 54;
+----+-------------+-------+------+-------------------------+------------+---------+-------+-------+-------------+
| id | select_type | table | type | possible_keys           | key        | key_len | ref   | rows  | Extra       |
+----+-------------+-------+------+-------------------------+------------+---------+-------+-------+-------------+
|  1 | SIMPLE      | devis | ref  | date_v_fin,date_v_fin_2 | date_v_fin | 9       | const | 15913 | Using where |
+----+-------------+-------+------+-------------------------+------------+---------+-------+-------+-------------+
1 row in set (0.34 sec)

以下是“好”优化查询的解释:

mysql> explain select date_v_creation from devis where etat=3   and date_v_creation < NOW() - INTERVAL 54 DAY   and date_v_fin is null;
+----+-------------+-------+-------+-----------------------------------------+-----------------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys                           | key             | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+-----------------------------------------+-----------------+---------+------+------+-------------+
|  1 | SIMPLE      | devis | range | date_v_fin,date_v_creation,date_v_fin_2 | date_v_creation | 9       | NULL | 1458 | Using where |
+----+-------------+-------+-------+-----------------------------------------+-----------------+---------+------+------+-------------+
1 row in set (0.00 sec)

3 个答案:

答案 0 :(得分:2)

你基本上有两个问题:

  1. 查询没有有用的键:这里有用的是包含方程式字段索引的键,然后进行比较。那就是你需要一个键(etat,date_v_creation)
  2. 目前无法使用date_v_creation上的索引,因为比较是在字段值的函数而不是值本身。这就是date_v_creation上的密钥没有帮助的原因。所以你应该按如下方式重写查询:

    select date_v_creation
    from devis
    where etat=3
      and date_v_creation < NOW() - INTERVAL 54 DAY
      and date_v_fin is null;
    

答案 1 :(得分:0)

@Olivier,这是一般的想法。如果您发布计划会更好。

  1. MySQL中的B-Tree索引不存储null。因此,如果您希望按column is null过滤掉smth,则应遵循以下策略(如果您确实需要它)。添加另一列is_null tinyint。将其设置为1或0.在其上创建索引。
  2. 关于etat。此列的选择性(=不同的行/所有行)值是多少?如果它很低,创建B-Tree索引不会影响性能到高。理想的选择性为1,但只能通过NOT NULL列上的唯一索引来达到这种选择性。

答案 2 :(得分:0)

date_v_creation未包含在您的索引中,因此MySQL仍然必须扫描表中的行才能执行SELECT。这是我的猜测,无论如何 - EXPLAIN SELECT...会告诉你查询计划员正在做什么的细节。

Null column values are indexed with MySQL b-trees.