찾다
데이터 베이스MySQL 튜토리얼简单谈谈MySQL的loose index scan_MySQL

众所周知,InnoDB采用IOT(index organization table)即所谓的索引组织表,而叶子节点也就存放了所有的数据,这就意味着,数据总是按照某种顺序存储的。所以问题来了,如果是这样一个语句,执行起来应该是怎么样的呢?语句如下:

select count(distinct a) from table1;

     列a上有一个索引,那么按照简单的想法来讲,如何扫描呢?很简单,一条一条的扫描,这样一来,其实做了一次索引全扫描,效率很差。这种扫描方式会扫描到很多很多的重复的索引,这样说的话优化的办法也是很容易想到的:跳过重复的索引就可以了。于是网上能搜到这样的一个优化的办法:

select count(*) from (select distinct a from table1) t;

    从已经搜索到的资料看,这样的执行计划中的extra就从using index变成了using index for group-by。

    但是,但是,但是,好在我们现在已经没有使用5.1的版本了,大家基本上都是5.5以上了,这些现代版本,已经实现了loose index scan:

     很好很好,就不需要再用这种奇技淫巧去优化SQL了。

     文档里关于group by这里写的有点意思,说是最大众化的办法就是进行全表扫描并且创建一个临时表,这样执行计划就会难看的要命了,肯定有ALL和using temporary table了。

5.0之后group by在特定条件下可能使用到loose index scan,

CREATE TABLE log_table (
id INT NOT NULL PRIMARY KEY,
log_machine VARCHAR(20) NOT NULL,
log_time DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX ix_log_machine_time ON log_table (log_machine, log_time);

1

SELECT MAX(log_time) FROM log_table;
SELECT MAX(log_time) FROM log_table WHERE log_machine IN ('Machine 1');

这两条sql都只需一次index seek便可返回,源于索引的有序排序,优化器意识到min/max位于最左/右块,从而避免范围扫描;
extra显示Select tables optimized away ;
2

代码如下:

SELECT MAX(log_time) FROM log_table WHERE log_machine IN (‘Machine 1','Machine 2','Machine 3','Machine 4');

执行计划type 为range(extra显示using where; using index),即执行索引范围扫描,先读取所有满足log_machine约束的记录,然后对其遍历找出max value;
改进

代码如下:

SELECT MAX(log_time) FROM log_table WHERE log_machine IN (‘Machine 1','Machine 2','Machine 3','Machine 4')  group by log_machine order by 1 desc limit 1;


这满足group by选择loose index scan的要求,执行计划的extra显示using index for group-by,执行效果等值于

SELECT MAX(log_time) FROM log_table WHERE log_machine IN (‘Machine 1')
Union
SELECT MAX(log_time) FROM log_table WHERE log_machine IN (‘Machine 2')
…..

即对每个log_machine执行loose index scan,rows从原来的82636下降为16(该表总共1,000,000条记录)。

Group by何时使用loose index scan?

适用条件:

1  针对单表操作
2  Group by使用索引的最左前缀列
3  只支持聚集函数min()/max()
4  Where条件出现的列必须为=constant操作 , 没出现在group by中的索引列必须使用constant
5  不支持前缀索引,即部分列索引 ,如index(c1(10))
执行计划的extra应该显示using index for group-by
假定表t1有个索引idx(c1,c2,c3)

SELECT c1, c2 FROM t1 GROUP BY c1, c2;
SELECT DISTINCT c1, c2 FROM t1;
SELECT c1, MIN(c2) FROM t1 GROUP BY c1;
SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2;
SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2;
SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2
SELECT c1, c3 FROM t1 GROUP BY c1, c2;--无法使用松散索引

而SELECT c1, c3 FROM t1  where c3= const GROUP BY c1, c2;则可以

紧凑索引扫描tight index scan
Group by在无法使用loose index scan,还可以选择tight,若两者都不可选,则只能借助临时表;
扫描索引时,须读取所有满足条件的索引键,要么是全索引扫描,要么是范围索引扫描;
Group by的索引列不连续;或者不是从最左前缀开始,但是where条件里出现最左列;

SELECT c1, c2, c3 FROM t1 WHERE c2 = &#39;a&#39; GROUP BY c1, c3;
SELECT c1, c2, c3 FROM t1 WHERE c1 = &#39;a&#39; GROUP BY c2, c3;

5.6的改进
事实上,5.6的index condition push down可以弥补loose index scan缺失带来的性能损失。
KEY(age,zip)

mysql> explain SELECT name FROM people WHERE age BETWEEN 18 AND 20 AND zip IN (12345,12346, 12347);
+----+-------------+--------+-------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra    |
+----+-------------+--------+-------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE   | people | range | age      | age | 4    | NULL | 90556 | Using where |
+----+-------------+--------+-------+---------------+------+---------+------+-------+-------------+
1 row in set (0.01 sec)

根据key_len=4可以推测出sql只用到索引的第一列,即先通过索引查出满足age (18,20)的行记录,然后从server层筛选出满足zip约束的行;
pre-5.6,对于复合索引,只有当引导列使用"="时才有机会在索引扫描时使用到后面的索引列。

mysql> explain SELECT name FROM people WHERE age=18 AND zip IN (12345,12346, 12347);
+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra    |
+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE   | people | range | age      | age | 8    | NULL |  3 | Using where |
+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

对比一下查询效率

mysql> SELECT sql_no_cache name FROM people WHERE age=19 AND zip IN (12345,12346, 12347);
+----------------------------------+
| name               |
+----------------------------------+
| 888ba838661aff00bbbce114a2a22423 |
+----------------------------------+
1 row in set (0.06 sec)
mysql> SELECT SQL_NO_CACHE name FROM people WHERE age BETWEEN 18 AND 22 AND zip IN (12345,12346, 12347);
+----------------------------------+
| name               |
+----------------------------------+
| ed4481336eb9adca222fd404fa15658e |
| 888ba838661aff00bbbce114a2a22423 |
+----------------------------------+
2 rows in set (1 min 56.09 sec)

对于第二条sql,可以使用union改写,

mysql> SELECT name FROM people WHERE age=18 AND zip IN (12345,12346, 12347)
  -> UNION ALL
  -> SELECT name FROM people WHERE age=19 AND zip IN (12345,12346, 12347)
  -> UNION ALL
  -> SELECT name FROM people WHERE age=20 AND zip IN (12345,12346, 12347)
  -> UNION ALL
  -> SELECT name FROM people WHERE age=21 AND zip IN (12345,12346, 12347)
  -> UNION ALL
-> SELECT name FROM people WHERE age=22 AND zip IN (12345,12346, 12347);

而mysql5.6引入了index condition pushdown,从优化器层面解决了此类问题。

 以上就是简单谈谈MySQL的loose index scan_MySQL的内容,更多相关内容请关注PHP中文网(www.php.cn)!


성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
index.html是什么文件?index.html是什么文件?Feb 19, 2024 pm 01:36 PM

index.html代表网页的首页文件,是网站的默认页面。当用户访问一个网站时,通常会首先加载index.html页面。HTML(HypertextMarkupLanguage)是一种用于创建网页的标记语言,index.html也是一种HTML文件。它包含网页的结构和内容,以及用于格式化和布局的标签和元素。下面是一个示例的index.html代码:<

mysql怎么替换换行符mysql怎么替换换行符Apr 18, 2022 pm 03:14 PM

在mysql中,可以利用char()和REPLACE()函数来替换换行符;REPLACE()函数可以用新字符串替换列中的换行符,而换行符可使用“char(13)”来表示,语法为“replace(字段名,char(13),'新字符串') ”。

mysql的msi与zip版本有什么区别mysql的msi与zip版本有什么区别May 16, 2022 pm 04:33 PM

mysql的msi与zip版本的区别:1、zip包含的安装程序是一种主动安装,而msi包含的是被installer所用的安装文件以提交请求的方式安装;2、zip是一种数据压缩和文档存储的文件格式,msi是微软格式的安装包。

mysql怎么将varchar转换为int类型mysql怎么将varchar转换为int类型May 12, 2022 pm 04:51 PM

转换方法:1、利用cast函数,语法“select * from 表名 order by cast(字段名 as SIGNED)”;2、利用“select * from 表名 order by CONVERT(字段名,SIGNED)”语句。

MySQL复制技术之异步复制和半同步复制MySQL复制技术之异步复制和半同步复制Apr 25, 2022 pm 07:21 PM

本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了关于MySQL复制技术的相关问题,包括了异步复制、半同步复制等等内容,下面一起来看一下,希望对大家有帮助。

带你把MySQL索引吃透了带你把MySQL索引吃透了Apr 22, 2022 am 11:48 AM

本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了mysql高级篇的一些问题,包括了索引是什么、索引底层实现等等问题,下面一起来看一下,希望对大家有帮助。

mysql怎么判断是否是数字类型mysql怎么判断是否是数字类型May 16, 2022 am 10:09 AM

在mysql中,可以利用REGEXP运算符判断数据是否是数字类型,语法为“String REGEXP '[^0-9.]'”;该运算符是正则表达式的缩写,若数据字符中含有数字时,返回的结果是true,反之返回的结果是false。

mysql需要commit吗mysql需要commit吗Apr 27, 2022 pm 07:04 PM

在mysql中,是否需要commit取决于存储引擎:1、若是不支持事务的存储引擎,如myisam,则不需要使用commit;2、若是支持事务的存储引擎,如innodb,则需要知道事务是否自动提交,因此需要使用commit。

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)