mysql:索引原理与慢查询优化

mysql:索引原理与慢查询优化,第1张

概述<h1class=\"js-evernote-checked\"data-evernote-id=\"789\"><strongclass=\"js-evernote-checked\"data-evernote-id=\"926\">一索引原理

<h1 data-evernote-ID="789"><strong data-evernote-ID="926">一 索引的原理

、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢?我们回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段......这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树,其平均复杂度是lgN,具有不错的查询性能。但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的。而数据库实现比较复杂,一方面数据是保存在磁盘上的,另外一方面为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景。

前面讲了索引的基本原理,数据库的复杂性,又讲了 *** 作系统的相关知识,目的就是让大家了解,任何一种数据结构都不是凭空产生的,一定会有它的背景和使用场景,我们现在总结一下,我们需要这种数据结构能够做些什么,其实很简单,那就是:每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级。那么我们就想到如果一个高度可控的多路搜索树是否能满足需求呢?就这样,b+树应运而生。

<p data-evernote-ID="763">如上图,是一颗b+树,关于b+树的定义可以参见B+树,这里只说一些重点,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非叶子节点只不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不真实存在于数据表中。


<p data-evernote-ID="764">###b+树的查找过程
如图所示,如果要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总计三次IO。真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。


<p data-evernote-ID="765">###b+树性质
1<strong data-evernote-ID="942"><span data-evernote-ID="943">.<span >索引字段要尽量的小:通过上面的分析,我们知道IO次数取决于b+数的高度h,假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N一定的情况下,m越大,h越小;而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小,数据项的数量越多,树的高度越低。这就是为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半。这也是为什么b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度下降,导致树增高。当数据项等于1时将会退化成线性表。
2.<span ><strong data-evernote-ID="945"><span data-evernote-ID="946">索引的最左匹配特性:当b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+数是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。


<p data-evernote-ID="765">


<h1 data-evernote-ID="791"><strong data-evernote-ID="950">三 MysqL索引管理
<h2 data-evernote-ID="765"><strong data-evernote-ID="951"><span data-evernote-ID="952">1. 功能
<div >

唯一索引:
-主键索引primary key:加速查找+<span >约束(不为空、不能重复)
-唯一索引unique:加速查找+<span >约束(不能重复)

联合索引(组合索引):
-<span >primary key(ID,name):联合主键索引
-<span >unique(ID,name):联合唯一索引
-index(ID,name):联合普通索引

这个系统有一个会员表
有下列字段:
会员编号 int
会员姓名 varchar(
10<span >)
会员身份z号码 varchar(18<span >)
会员电话 varchar(10<span >)
会员住址 varchar(50<span >)
会员备注信息 text

那么这个 会员编号,作为主键,使用 primary
会员姓名 如果要建索引的话,那么就是普通的 index
会员身份z号码 如果要建索引的话,那么可以选择 unique (唯一的,不允许重复)

<span >#<span >除此之外还有全文索引,即FulLTEXT
<span >会员备注信息 , 如果需要建索引的话,可以选择全文搜索。
用于搜索很长一篇文章的时候,效果最好。
用在比较短的文本,如果就一两行字的,普通的 index 也可以。
但其实对于全文搜索,我们并不会使用MysqL自带的该索引,而是会选择第三方软件如Sphinx,专门来做全文搜索。

<span >#<span >其他的如空间索引SPATIAL,了解即可,几乎不用

+<span >#<span >不同的存储引擎支持的索引类型也不一样
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-<span >text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B
-tree、Full-<span >text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B
-tree、Hash 等索引,不支持 Full-<span >text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-<span >text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;

1<span >#<span >方法一:创建表时
-<span > 在创建表时就创建
  create table 表名 (
字段名1 数据类型 [完整性约束条件&hellip;],字段名2 数据类型 [完整性约束条件&hellip;],[unique | fulltext | spatial ] index |<span > key
[索引名] (字段名[(长度)] [asc |<span >desc])
);
<span >#<span >例:
<span > create table s1(
ID int,name char(6<span >),age int,email varchar(30<span >),index(ID) <span >#<span >不是约束条件,故不能直接跟在字段后面
<span > );

<span >#<span >方法二:CREATE在已存在的表上创建索引
create [unique | fulltext |<span > spatial ] index 索引名
on 表名 (字段名[(长度)] [asc |<span >desc]) ;

<span >#<span >例 - 在创建表后创建
create index name on s1(name);<span >#<span >添加普通索引
create unique index age on s1(age);<span >#<span >添加唯一索引
create index name on s1(ID,name);<span >#<span >添加联合普通索引

<span >#<span >方法三:ALTER table在已存在的表上创建索引
alter table 表名 add [unique | fulltext |<span > spatial ] index
索引名 (字段名[(长度)] [asc |<span >desc]) ;
<span >#<span >例:
alter table s1 add primary key(ID);<span >#<span >添加主键索引

2<span > 删除索引
<span >#<span > 删除索引:DROP INDEX 索引名 ON 表名字;<span >

<span >例:

drop index ID on s1;
drop index name on s1;
alter table s1 drop primary key;<span > # 删除主键索引

<h1 data-evernote-ID="792"><strong data-evernote-ID="962">四 测试索引

20650<span >#<span >2. 创建存储过程,实现批量插入记录
delimiter $$ <span >#
<span >声明存储过程的结束符号为$$

<span >create procedure auto_insert1()
BEGIN
declare i int default
1<span >;
<span >while(i<300000)do <span >#<span >插入比较慢,耗时比较长
insert into s1 values(i,concat(<span >'<span >egon<span >',i),<span >'<span >male<span >',i,<span >'<span >@oldboy<span >'<span >));
set i=i+1<span >;
end <span >while<span >;
END$$ <span >#<span >$$结束
delimiter ; <span >#<span >重新声明分号为结束符号

<span >#<span >3. 查看存储过程
<span >show create procedure auto_insert1\G

<span >#<span >4. 调用存储过程
call auto_insert1();

MysqL> select * s1 where ID=333+------+---------+--------+----------------+| ID | name | gender | email |+------+---------+--------+----------------+| 333 | egon333 | male | egon333@oldboy |+------+---------+--------+----------------+1 row set (0.17MysqL> select * <span >from s1 where email=<span >'<span >egon333@oldboy<span >'<span >;
+------+---------+--------+----------------+
| ID | name | gender | email |
+------+---------+--------+----------------+
| 333 | egon333 | male | egon333@oldboy |
+------+---------+--------+----------------+
1 row <span >in set (0.15 sec)

<span >#<span >2. 在表中已经有大量数据的情况下,建索引会很慢,且占用硬盘空间,插入删除更新都很慢,只有查询快
<span >比如create index IDx on s1(ID);会扫描表中所有的数据,然后以ID为数据项,创建索引结构,存放于硬盘的表中。
建完以后,再查询就会很快了

<span >#<span >3. 需要注意的是:innodb表的索引会存放于s1.ibd文件中,而myisam表的索引则会有单独的索引文件table1.MYI

<h1 data-evernote-ID="793">五 正确使用索引

MysqL> select count(*) s1 where ID=1000+----------+| count(*) |+----------+| 1 |+----------+1 row set (0.00MysqL> select count() <span >from s1 where ID>1000<span >;
+----------+
| count(
) |
+----------+
| 298999 |
+----------+
1 row <span >in
set (0.11<span > sec)

MysqL> select count() <span >from s1 where ID>1000 <span >and ID < 2000<span >;
+----------+
| count(
) |
+----------+
| 999 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where ID>1000 <span >and ID < 300000<span >;
+----------+
| count(
) |
+----------+
| 298999 |
+----------+
1 row <span >in set (0.13 sec)

-//blog.itpub.net/22664653/vIEwspace-774667/

<span >#<span >分析
select <span >from s1 where ID=123<span >;
该sql命中了索引,但未覆盖索引。
利用ID=<span >123到索引的数据结构中定位到该ID在硬盘中的位置,或者说再数据表中的位置。
但是我们select的字段为
<span >,除了ID以外还需要其他字段,这就意味着,我们通过索引结构取到ID还不够,还需要利用该ID再去找到该ID所在行的其他字段值,这是需要时间的,很明显,如果我们只select ID,就减去了这份苦恼,如下
select ID <span >from s1 where ID=123<span >;
这条就是覆盖索引了,命中索引,且从索引的数据结构直接就取到了ID在硬盘的地址,速度很快

<div >

<span >#<span >分析:
<span >组合索引能做到的事情,我们都可以用索引合并去解决,比如
create index ne on s1(name,email);<span >#<span >组合索引
<span >我们完全可以单独为name和email创建索引

组合索引可以命中:
select <span >from s1 where name=<span >'<span >egon<span >'<span > ;
select
<span >from s1 where name=<span >'<span >egon<span >' <span >and email=<span >'<span >adf<span >'<span >;

索引合并可以命中:
select <span >from s1 where name=<span >'<span >egon<span >'<span > ;
select
<span >from s1 where email=<span >'<span >adf<span >'<span >;
select * <span >from s1 where name=<span >'<span >egon<span >' <span >and email=<span >'<span >adf<span >'<span >;

乍一看好像索引合并更好了:可以命中更多的情况,但其实要分情况去看,如果是name=<span >'<span >egon<span >' <span >and email=<span >'<span >adf<span >',那么组合索引的效率要高于索引合并,如果是单条件查,那么还是用索引合并比较合理

-* s1 where name=; select * s1 where name= email=; select * s1 where email=; MysqL会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 b = 2 c > 3 d = 4<span >#<span >2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,c)索引可以任意顺序,MysqL的查询优化器会帮你优化成索引可以识别的形式

<span >#<span >3.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录

<span >#<span >4.索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);

<span >#<span >5.尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可

<div onclick="cnblogs_code_show('fed8dbea-9c3e-4455-8be2-bc1eac3694bf')">


<div ID="cnblogs_code_open_fed8dbea-9c3e-4455-8be2-bc1eac3694bf" >

1> select count(*)  s1 where ID=1000+----------+| count(*) |+----------+|        1 |+----------+1 row  set (0.12MysqL> select count() <span >from s1 where ID>1000<span >;
+----------+
| count(
) |
+----------+
| 298999 |
+----------+
1 row <span >in
set (0.12<span > sec)

MysqL><span > create index a on s1(ID)
-><span > ;
query OK,0 rows affected (3.21<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select count() <span >from s1 where ID=1000<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where ID>1000<span >;
+----------+
| count(
) |
+----------+
| 298999 |
+----------+
1 row <span >in set (0.12<span > sec)

MysqL> select count() <span >from s1 where ID>1000 <span >and ID < 2000<span >;
+----------+
| count(
) |
+----------+
| 999 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where ID>1000 <span >and ID < 300000<span >;
+----------+
| count(
) |
+----------+
| 298999 |
+----------+
1 row <span >in set (0.13<span > sec)

3<span > 区分度低的字段不能加索引
MysqL> select count() <span >from s1 where name=<span >'<span >xxx<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >'<span >;
+----------+
| count(
) |
+----------+
| 299999 |
+----------+
1 row <span >in set (0.19<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=123123123123123<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.45<span > sec)

MysqL><span > create index c on s1(age);
query OK,0 rows affected (3.03<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=123123123123123<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10<span >;
+----------+
| count(
) |
+----------+
| 299999 |
+----------+
1 row <span >in set (0.35<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10 <span >and ID>3000 <span >and ID < 4000<span >;
+----------+
| count(
) |
+----------+
| 999 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10 <span >and ID>3000 <span >and email=<span >'<span >xxxx<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.47<span > sec)

MysqL><span > create index d on s1(email);
query OK,0 rows affected (4.83<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10 <span >and ID>3000 <span >and email=<span >'<span >xxxx<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL><span > drop index a on s1;
query OK,0 rows affected (0.10<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL><span > drop index b on s1;
query OK,0 rows affected (0.09<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL><span > drop index c on s1;
query OK,0 rows affected (0.09<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL><span > desc s1;
+-------+-------------+------+-----+---------+-------+
| FIEld | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| ID | int(11) | NO | | NulL | |
| name | char(20) | YES | | NulL | |
| age | int(11) | YES | | NulL | |
| email | varchar(30) | YES | Mul | NulL | |
+-------+-------------+------+-----+---------+-------+
4 rows <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10 <span >and ID>3000 <span >and email=<span >'<span >xxxx<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

5<span > 增加联合索引,关于范围查询的字段要放到后面
select count(*) <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10 <span >and ID>3000 <span >and email=<span >'<span >xxxx<span >'<span >;
index(name,ID)

select count(*) <span >from s1 where name=<span >'<span >egon<span >' <span >and age> 10 <span >and ID=3000 <span >and email=<span >'<span >xxxx<span >'<span >;
index(name,ID,age)

select count(*) <span >from s1 where name like <span >'<span >egon<span >' <span >and age= 10 <span >and ID=3000 <span >and email=<span >'<span >xxxx<span >'<span >;
index(email,name)

MysqL><span > desc s1;
+-------+-------------+------+-----+---------+-------+
| FIEld | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| ID | int(11) | NO | | NulL | |
| name | char(20) | YES | | NulL | |
| age | int(11) | YES | | NulL | |
| email | varchar(30) | YES | | NulL | |
+-------+-------------+------+-----+---------+-------+
4 rows <span >in set (0.00<span > sec)

MysqL><span > create index xxx on s1(age,name,ID);
query OK,0 rows affected (6.89<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >' <span >and age=10 <span >and ID>3000 <span >and email=<span >'<span >xxxx<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

6<span >. 最左前缀匹配:必须按照从左到右的顺序匹配
index(ID,name)
<span >#<span >条件中一定要出现ID
<span >ID
ID age
ID email
ID name

email <span >#<span >不行
MysqL> select count() <span >from s1 where ID=3000<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.11<span > sec)

MysqL><span > create index xxx on s1(ID,email);
query OK,0 rows affected (6.44<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select count() <span >from s1 where ID=3000<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >'<span >;
+----------+
| count(
) |
+----------+
| 299999 |
+----------+
1 row <span >in set (0.16<span > sec)

MysqL> select count() <span >from s1 where email=<span >'<span >egon3333@oldboy.com<span >'<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.15<span > sec)

MysqL> select count() <span >from s1 where ID=1000 <span >and email=<span >'<span >egon3333@oldboy.com<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where email=<span >'<span >egon3333@oldboy.com<span >' <span >and ID=3000<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

6<span >.索引列不能参与计算,保持列“干净”

MysqL> select count() <span >from s1 where ID=3000<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.11<span > sec)

MysqL><span > create index xxx on s1(ID,0 rows affected (6.44<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select count() <span >from s1 where ID=3000<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where name=<span >'<span >egon<span >'<span >;
+----------+
| count(
) |
+----------+
| 299999 |
+----------+
1 row <span >in set (0.16<span > sec)

MysqL> select count() <span >from s1 where email=<span >'<span >egon3333@oldboy.com<span >'<span >;
+----------+
| count(
) |
+----------+
| 1 |
+----------+
1 row <span >in set (0.15<span > sec)

MysqL> select count() <span >from s1 where ID=1000 <span >and email=<span >'<span >egon3333@oldboy.com<span >'<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00<span > sec)

MysqL> select count() <span >from s1 where email=<span >'<span >egon3333@oldboy.com<span >' <span >and ID=3000<span >;
+----------+
| count(
) |
+----------+
| 0 |
+----------+
1 row <span >in set (0.00 sec)

select * s1 where ID>3 name= email= gender=0.39MysqL> create index IDx on s1(ID,gender); <span >#<span >未遵循最左前缀
query OK,0 rows affected (15.27<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select * <span >from s1 where ID>3 <span >and name=<span >'<span >egon<span >' <span >and email=<span >'<span >alex333@oldboy.com<span >' <span >and gender=<span >'<span >male<span >'<span >;
Empty set (0.43<span > sec)

MysqL><span > drop index IDx on s1;
query OK,0 rows affected (0.16<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> create index IDx on s1(name,gender,ID); <span >#<span >遵循最左前缀
query OK,0 rows affected (15.97<span > sec)
Records: 0 Duplicates: 0 Warnings: 0

MysqL> select * <span >from s1 where ID>3 <span >and name=<span >'<span >egon<span >' <span >and email=<span >'<span >alex333@oldboy.com<span >' <span >and gender=<span >'<span >male<span >'<span >;
Empty set (0.03 sec)

* tb1 where email like -<span > 使用函数
select
* <span >from
tb1 where reverse(email) = <span >'
<span >wupeiqi
<span >'
<span >;

- <span >or<span >
select * <span >from tb1 where nID = 1 <span >or name = <span >'<span >seven@live.com<span >'<span >;

特别的:当or<a href="https://m.jb51.cc/tag/tiaojian/" target="_blank" >条件</a>中有未建立索引的列才<a href="https://m.jb51.cc/tag/shixiao/" target="_blank" >失效</a>,以下会走索引        select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> tb1 where n<a href="https://m.jb51.cc/tag/ID/" target="_blank" >ID</a> = 1 <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;or</span> <a href="https://m.jb51.cc/tag/name/" target="_blank" >name</a> = <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;seven</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt;;        select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> tb1 where n<a href="https://m.jb51.cc/tag/ID/" target="_blank" >ID</a> = 1 <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;or</span> <a href="https://m.jb51.cc/tag/name/" target="_blank" >name</a> = <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;seven@<a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>ve.com</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span> <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;and</span> email = <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;alex</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span>

-<span > 类型不一致
如果列是字符串类型,传入条件是必须用引号引起来,不然...
select * <span >from tb1 where email = 999<span >;

普通索引的不等于不会走索引
- !=<span >
select * <span >from tb1 where email != <span >'<span >alex<span >'<span >

特别的:如果是主键,则还是会走索引    select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> tb1 where n<a href="https://m.jb51.cc/tag/ID/" target="_blank" >ID</a> != 123

<span >
select * <span >from tb1 where email > <span >'<span >alex<span >'<span >

特别的:如果是主键或索引是整数类型,则还是会走索引
select <span >from tb1 where nID > 123<span >
select
<span >from tb1 where num > 123

<span >#<span >排序条件为索引,则select字段必须也是索引字段,否则无法命中
-<span > order by
select name <span >from<span > s1 order by email desc;
当根据索引排序时候,select查询的字段如果不是索引,则不走索引
select email <span >from<span > s1 order by email desc;
特别的:如果对主键排序,则还是走索引:
select * <span >from<span > tb1 order by nID desc;

-<span > 组合索引最左前缀
如果组合索引为:(name,email)
name <span >and email --<span > 使用索引
name --<span > 使用索引
email --<span > 不使用索引

- count(1)或count(列)代替count(*<span >)在MysqL中没有差别了

- create index xxxx on tb(Title(19)) <span >#<span >text类型,必须制定长度

- 避免使用select *- count(1)或count(列) 代替 count(*----- 使用连接(JOIN)来代替子查询(Sub--- 索引散列值(重复高的)不适合建索引,例:性别不适合六 查询优化神器-explain

关于explain命令相信大家并不陌生,具体用法和字段含义可以参考官网href="http://dev.MysqL.com/doc/refman/5.5/en/explain-output.HTML">explain-output,这里需要强调rows是核心指标,绝大部分rows小的语句执行一定很快(有例外,下面会讲到)。所以优化语句基本上都是在优化rows。

< index < range < index_merge < ref_or_null < ref < eq_ref < system/慢: select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> userinfo3 where <a href="https://m.jb51.cc/tag/name/" target="_blank" >name</a>=<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;alex</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; explain select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> userinfo3 where <a href="https://m.jb51.cc/tag/name/" target="_blank" >name</a>=<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;alex</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; type: ALL(全表扫描) select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> userinfo3 <a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>mit 1<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt;;快: select </span>* <span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;from</span> userinfo3 where email=<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;alex</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; type: const(走索引)</span></pre>

http://blog.itpub.net/29773961/vIEwspace-1767044/

七 慢查询优化的基本步骤123456.观察结果,不符合预期继续从0分析八 慢日志管理- 执行时间 > 10 -- 配置: </span>-<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; 内存 show variables <a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>ke </span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;%<a href="https://m.jb51.cc/tag/query/" target="_blank" >query</a>%</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt;; show variables <a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>ke </span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;%quer<a href="https://m.jb51.cc/tag/IE/" target="_blank" >IE</a>s%</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt;; set </span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #0000ff;"&gt;global</span> 变量名 =<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; 值 </span>-<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; <a href="https://www.jb51.cc/tag/peizhiwenjian/" target="_blank" >配置文件</a> <a href="https://www.jb51.cc/tag/MysqL/" target="_blank" >MysqL</a>d </span>--defa<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>ts-<a href="https://m.jb51.cc/tag/file/" target="_blank" >file</a>=<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;E:\wupeiqi\<a href="https://www.jb51.cc/tag/MysqL/" target="_blank" >MysqL</a>-5.7.16-winx64\<a href="https://www.jb51.cc/tag/MysqL/" target="_blank" >MysqL</a>-5.7.16-winx64\my-defa<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>t.ini</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #800000;"&gt;'</span><span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; my.conf<a href="https://www.jb51.cc/tag/neirong/" target="_blank" >内容</a>: slow_<a href="https://m.jb51.cc/tag/query/" target="_blank" >query</a>_log </span>=<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt; ON slow_<a href="https://m.jb51.cc/tag/query/" target="_blank" >query</a>_log_<a href="https://m.jb51.cc/tag/file/" target="_blank" >file</a> </span>= D:/<span https://m.jb51.cc/tag/color/" target="_blank" >color</a>: #000000;"&gt;.... 注意:<a href="https://www.jb51.cc/tag/xiugai/" target="_blank" >修改</a><a href="https://www.jb51.cc/tag/peizhiwenjian/" target="_blank" >配置文件</a>之后,需要重启服务</span></pre>

<div onclick="cnblogs_code_show('67c81b6e-3e35-467b-8446-c425476ecd1c')">


<div ID="cnblogs_code_open_67c81b6e-3e35-467b-8446-c425476ecd1c" >

================================================================================================================-1-bin[=2//==134. 截断bin-log(产生新的bin-5. 删除bin-二、查询日志
启用通用查询日志
<span >#
<span > vim /etc/my.cnf

<span >[MysqLd]
log[
=<span >dir[filename]]
<span >#
<span > service MysqLd restart

<span >
三、慢查询日志
启用慢查询日志
<span >#
<span > vim /etc/my.cnf

<span >[MysqLd]
log
-slow-querIEs[=<span >dir[filename]]
long_query_time
=<span >n
<span >#
<span > service MysqLd restart

MysqL 5.6<span >:
slow
-query-log=1<span >
slow
-query-log-file=<span >slow.log
long_query_time
=3<span >
查看慢查询日志
测试:BENCHMARK(count,expr)
SELECT BENCHMARK(
50000000,2*3);

<p data-evernote-ID="765">

总结

以上是内存溢出为你收集整理的mysql:索引原理与慢查询优化全部内容,希望文章能够帮你解决mysql:索引原理与慢查询优化所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1169508.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-02
下一篇 2022-06-02

发表评论

登录后才能评论

评论列表(0条)