索引是一种利用某种规定的数据结构与理论数据的关系放慢数据查找的性能。咱们的数据库中存储有大量的内容,而索引可能通过数据节点,依据特定的规定和算法疾速查找到节点对应的理论文件的地位。简略来说索引就像书的目录,可能帮忙咱们精确定位到书籍具体的内容。
最近在学习索引的时候遇到了一个问题,上面咱们通过重现的形式来看一下。
首先建设一个如下测试表:
CREATE TABLE `simple_table` (
`id` int NOT NULL AUTO_INCREMENT,
`c1` datetime DEFAULT NULL,
`c2` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c2__idx` (`c2`),
KEY `fun_c1_idx` ((cast(`c1` as date)))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
fun_c1_idx: 是 mysql8 开始反对的函数索引
而后往这个表里随机插入 1000 条数据。
select * from simple_table where date(c2) = '2022-01-01';
能够看到下面的这条 SQL 语句不能走索引。因为索引树中存储的是列的理论值和主键值,所以对条件字段做函数操作是会让索引生效的。简略来说就是,如果拿‘2022-01-01’去匹配,将无奈定位到索引树中的值。因而正确抉择是放弃走索引,抉择全表扫描。
咱们再看下一条 SQL。
select id,c2 from simple_table where date(c2) = '2022-01-01';
与第一条不同,这条 SQL 只返回了局部列,而且这些列都在索引中了。而后咱们用 explain 剖析一下这条 SQL 的执行打算,判断它是否走索引:
上图能够显著看到 key 值为c2__idx
,即走了索引。
这里就很奇怪,不是说对条件字段做函数操作是会让索引生效吗,为什么这里又走了索引?
这就是我过后在学习时遇到的问题,起初我发现是因为我没有搞清楚“走索引”的意思。大家都晓得索引能放慢查问,然而索引能放慢查问的起因你晓得么?答案是缩小了查问的次数。
当初咱们回到下面的 SQL,能够看到尽管 key 值为 c2__idx
,然而 rows 值为 1000。也就是扫描了扫描全表,即 c2__idx
的所有记录。然而因为 c2__idx
曾经蕴含了所有须要查问的列,优化器才抉择了走这个索引。
最初再来思考一个问题,应用了索引是否肯定快?这个问题咱们通过一个具体例子看一下:
select * from simple_table;
select * from simple_table where id > 0;
不须要 explain 剖析间接肉眼察看就能看到第一条 SQL 没有走索引,第二条 SQL 应用了主键索引。能够看到没有应用索引的速度快一些,这是因为尽管应用了索引,然而还是从主键索引的最右边的叶节点开始向右扫描整个索引树,进行了全表扫描,这让索引失去了意义。
总结一下:查问是否应用索引,只是示意一个 SQL 语句的执行过程;而是否为慢查问,是由它执行的工夫决定的,也就是说是否应用了索引和是否是慢查问两者之间没有必然的分割。咱们在应用索引时,不应只关注是否起作用,而应该关怀索引是否缩小了查问扫描的数据行数,扫描行数缩小效率才会失去晋升。对于一个大表,不止要创立索引,还要思考索引过滤性,过滤性好,执行速度才会快。
举荐浏览
Base64 编码常识,一文打尽!
Golang 常见设计模式之单例模式