我有以下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';
当我添加其他索引KEY newkey
(a_id
,state
,start_time
)时,MySQL仍然只尝试使用a_id而不是newkey。只有在查询中使用提示/强制索引时,才会使用它。更改查询中的字段无济于事。
有什么想法吗?我不一定要在我的陈述中提示。 MySQL没有这样做的事实自动向我表明我的表,密钥或查询存在问题。任何帮助都非常感谢。
其他信息:
mysql> show index in tasks;
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tasks | 0 | PRIMARY | 1 | id | A | 3130554 | NULL | NULL | | BTREE | | |
| tasks | 1 | a_id | 1 | a_id | A | 2992 | NULL | NULL | YES | BTREE | | |
| tasks | 1 | job | 1 | job | A | 5 | NULL | NULL | | BTREE | | |
| tasks | 1 | state | 1 | state | A | 9 | NULL | NULL | | BTREE | | |
| tasks | 1 | end_time | 1 | end_time | A | 1565277 | NULL | NULL | | BTREE | | |
| tasks | 1 | newkey | 1 | a_id | A | 2992 | NULL | NULL | YES | BTREE | | |
| tasks | 1 | newkey | 2 | state | A | 8506 | NULL | NULL | | BTREE | | |
| tasks | 1 | newkey | 3 | start_time | A | 3130554 | NULL | NULL | | BTREE | | |
+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
使用和不使用引号进行解析:
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)
答案 0 :(得分:1)
一些事情......我会有一个单一的复合索引 (a_id,job,state,start_time)
这有助于优化所有标准的查询,我认为是最好的调整序列。单个“A_ID”,然后是两个作业,一个小的状态范围,然后基于时间。接下来,请注意没有引号......看起来您正在将数字转换为字符串比较,将它们保留为比较数字 - 比字符串更快。
此外,通过将它们全部作为索引的一部分,它是一个COVERING索引,这意味着它不必转到原始页面数据来获取其他值来测试合格记录是否包含。
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”,其中包括按顺序排列的作业,每个作业中的状态范围,最后是开始时间。
在另一个房间,您的方框按开始时间排序,其中a_id已排序,最后状态。
哪个更容易找到你需要的东西。这就是你应该如何考虑索引。我宁愿去一个方框“A_ID = 614”,然后跳到Job 1,另一个用于Job 3.在每个Job 1,Job 3中,抓80-100,然后是时间。但是,您可以更好地了解每个标准考虑因素中的数据和数量,并可能进行调整。
最后,计数(ID)与计数(*)。我所关心的只是一个合格的记录。我不需要知道实际的ID,因为过滤标准已经被认定为包括或不包括,为什么看(在这种情况下)实际的“ID”。
答案 1 :(得分:0)
可能mysql认为使用a_id密钥会使用更少的IO。 关键字a_id的基数可能已经足够了。 暗示/暗示查询的解释是什么?
答案 2 :(得分:0)
大多数a_id=614
的州都有&gt; 80和&lt; 100,那么它可能会发生。您是否尝试过以下索引之一?
INDEX(a_id, start_time, state)
INDEX(start_time, a_id, state)