IN子句不使用索引

时间:2016-06-30 03:58:27

标签: mysql indexing

这是表格定义

CREATE TABLE `dt_prdtime` (
  `TCompany` varchar(3) NOT NULL DEFAULT '',
  `TPerCode` varchar(8) NOT NULL,
  `TBegDateTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'วันที่',
  `TQPay` int(1) NOT NULL DEFAULT '2',
  `TYear` int(4) NOT NULL,
  `TMonth` int(2) NOT NULL,
  PRIMARY KEY (`TCompany`,`TPerCode`,`TBegDateTime`),
  KEY `TMonth` (`TMonth`) USING BTREE,
  KEY `TPerCode` (`TPerCode`,`TYear`,`TMonth`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

这是数据样本。此表有10000多条记录,TMonth字段中的值各不相同

+----------+----------+---------------------+-------+-------+--------+
| TCompany | TPerCode | TBegDateTime        | TQPay | TYear | TMonth |
+----------+----------+---------------------+-------+-------+--------+
| S10      | 000001   | 2016-01-02 17:33:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-02 07:48:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-03 17:39:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-03 07:30:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-04 17:49:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-04 07:54:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-05 17:50:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-05 07:36:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-06 17:37:00 |     1 |  2016 |      1 |
| S10      | 000001   | 2016-01-06 07:35:00 |     1 |  2016 |      1 |
+----------+----------+---------------------+-------+-------+--------+

使用EXPLAIN,此查询使用TMonth索引:

SELECT * FROM dt_prdtime WHERE TMonth = 5

虽然这个拒绝使用索引:

SELECT * FROM dt_prdtime WHERE TMonth IN (5,6)

我用另一个简单的表格测试了

CREATE TABLE `table1` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

SELECT * FROM table2 WHERE id IN (5,6)

并使用了该表的索引

有人可以解释一下吗? dt_prdtime表格有问题吗?

2 个答案:

答案 0 :(得分:2)

我会说,这是因为你使用的是MyISAM引擎。

在我的Answer中可以看到它与INNODB的完美结合。

我会尽力在这个问题上起到至少一个光荣的参考。

这里,The range Join Type,显然是INNODB焦点,因为它是默认引擎。如果在某些文档层次结构的手册中没有明确提到,则会假定它。

注意,我的示例链接中的id没有任何连续性。意思是,不要在其EXPLAIN输出中对type=range进行超聚焦。速度通过优化器(CBO)得出。

我的例子中的cardinality非常高(4.3百万)。目标id计数相对较低(1000)。使用索引。

您的情况可能相反:您的基数可能非常低,如3,优化程序决定放弃使用索引。

要检查索引cardinality,请参阅手册页SHOW INDEX Syntax

一个简单的电话,例如:

show index from ratings;

+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| ratings |          0 | PRIMARY  |            1 | id          | A         |     4313544 |     NULL | NULL   |      | BTREE      |         |               |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

答案 1 :(得分:0)

当需要获取“太多”的表时,MyISAM和InnoDB都不可能使用索引。

IN (5,6)可能意味着需要扫描表的2/12?或者数据可能存在偏差,以至于这两个月的行数超过它们的份额?

优化器可能在这种情况下避开索引的原因......

使用这样的索引时,需要花费大量时间在索引(一个BTree)和数据之间反弹。

当不使用索引时,它只是通过数据巡航,忽略行的10/12。 可能实际上更快。