MySQL索引使用查询优化

MySQL索引使用查询优化,mysql,indexing,Mysql,Indexing,我有下面的MySQL MyISAM表,大约有300万行 CREATE TABLE `tasks` ( `id` int(11) NOT NULL AUTO_INCREMENT, `node` smallint(6) NOT NULL, `pid` int(11) NOT NULL, `job` int(11) NOT NULL, `a_id` int(11) DEFAULT NULL, `user_id` int(11) NOT NULL, `state` int(1

我有下面的MySQL MyISAM表,大约有300万行

CREATE TABLE `tasks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `node` smallint(6) NOT NULL,
  `pid` int(11) NOT NULL,
  `job` int(11) NOT NULL,
  `a_id` int(11) DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  `state` int(11) NOT NULL,
  `start_time` int(11) NOT NULL,
  `end_time` int(11) NOT NULL,
  `stop_time` int(11) NOT NULL,
  `end_stream` int(11) NOT NULL,
  `message` varchar(255) DEFAULT NULL,
  `rate` float NOT NULL,
  `exiting` int(11) NOT NULL DEFAULT '0',
  `bytes` int(11) NOT NULL,
  `motion` tinyint(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `a_id` (`a_id`),
  KEY `job` (`job`),
  KEY `state` (`state`),
  KEY `end_time` (`end_time`),
  KEY `start_time` (`start_time`),
) ENGINE=MyISAM AUTO_INCREMENT=100 DEFAULT CHARSET=utf8;
现在,当我运行以下查询时,MySQL只使用a_id索引,需要扫描几千行

SELECT count(id) AS tries FROM `tasks` WHERE ( job='1' OR job='3' ) 
AND a_id='614' AND state >'80' AND state < '100' AND start_time >='1386538013';
用引号和不用引号解释:

mysql> DESCRIBE SELECT count(id) AS tries FROM `tasks` WHERE ( job='1' OR job='3' )  AND a_id='614' AND state >'80' AND state < '100' AND start_time >='1386538013';
+----+-------------+-------+------+----------------------------+-----------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys              | key       | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+----------------------------+-----------+---------+-------+------+-------------+
|  1 | SIMPLE      | tasks | ref  | a_id,job,state,newkey      | a_id      | 5       | const |  740 | Using where |
+----+-------------+-------+------+----------------------------+-----------+---------+-------+------+-------------+
1 row in set (0.10 sec)

mysql> DESCRIBE SELECT count(id) AS tries FROM `tasks` WHERE ( job=1 OR job=3 )  AND a_id = 614 AND state > 80 AND state < 100 AND start_time >= 1386538013;
+----+-------------+-------+------+----------------------------+-----------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys              | key       | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+----------------------------+-----------+---------+-------+------+-------------+
|  1 | SIMPLE      | tasks | ref  | a_id,job,state,newkey      | a_id      | 5       | const |  740 | Using where |
+----+-------------+-------+------+----------------------------+-----------+---------+-------+------+-------------+
1 row in set (0.01 sec)

可能mysql认为使用a_id键将使用更少的IO。 可能密钥a_id的基数已经足够好了。 暗示/轻率查询的解释是什么?

大多数a_id=614的状态都是>80和<100,那么它就有可能发生。您是否尝试过以下索引之一

索引id、开始时间、状态 索引开始时间、id、状态
有几件事。。。我会有一个单一的复合索引 id、作业、状态、开始时间

这有助于优化所有条件的查询,我认为这是最佳优化顺序。一个单一的A_ID,然后两个工作,一个小的状态范围,然后基于时间。接下来,请注意没有引号。。。似乎您正在将数字转换为字符串比较,将它们保留为数字进行比较-比字符串快

此外,通过将它们都作为索引的一部分,它是一个覆盖索引,这意味着它不必转到原始页面数据来获取其他值来测试是否包含符合条件的记录

SELECT 
      count(*) AS tries 
   FROM 
      tasks
   WHERE 
          a_id = 614
      AND job IN ( 1, 3 ) 
      AND state > 80 AND state < 100 
      AND start_time >= 1386538013;
现在,为什么索引。。。考虑下面的场景。你有两个有盒子的房间。。。在第一个房间中,每个框都是一个a_id,其中依次是作业,每个作业中都是状态范围,最后是开始时间

在另一个房间中,您的框将按开始时间排序,在该时间内,将对一个_id进行排序,并最终显示状态

这样更容易找到你需要的东西。这就是你对索引的看法。我宁愿去一个盒子,一个ID=614,然后跳转到作业1,另一个跳转到作业3。在每个作业1、作业3中,抓取80-100,然后抓取时间。但是,您更了解每个标准考虑因素中的数据和数量,并且可能会进行调整


最后,countID与count*。我关心的只是一张合格的唱片。我不需要知道实际ID,因为筛选条件已经被限定为包含或不包含,为什么在本例中查找实际ID。

为什么在选择中使用静态数字作为字符串?这可能会使查询优化器失效。感谢您让我知道,我不确定这是否会有很大的区别,但不会解释,但会尽量避免不必要的引用。我认为问题是,作业列不在这两个索引中。无论使用哪个索引,它都必须引用完整的表才能满足where子句的这一部分。行查找可能主导IO,因此索引的选择无关紧要。如果在原始PostDrapp中添加了descripe语句和索引信息,这一切都是有意义的-这样做会使MySQL使用newkey而不仅仅是a_id。星形有意义,in子句也有意义。谢谢你,开心吧。@user2785818,欢迎你,作为一个新手,通常在给出答案时,如果答案有意义/有用,你可以向上投票,然后选择答案旁边的复选标记,这样其他人也知道答案已经解决。谢谢你让我知道-投票还需要4个经验点:谢谢,大多数州在80到100之间。是的,选择正确的索引是关键。
SELECT 
      count(*) AS tries 
   FROM 
      tasks
   WHERE 
          a_id = 614
      AND job IN ( 1, 3 ) 
      AND state > 80 AND state < 100 
      AND start_time >= 1386538013;