Mysql之索引
什么是索引?
是一种高效获取数据的数据结构,它是有序的。
优缺点
优点:可以提高查询效率,降低io成本。
缺点:占用部分空间,更新表需要更新索引。
B树
是一种自平衡的树数据结构,B树的每个节点可以拥有多个子节点,即b树的阶层,每个节点key数量为阶层-1。
B+树
所有数据指针放置在叶子节点,叶子节点通过一个双向链表连接,方便范围查找。
B树和B+树的区别?
存储方式不同:B树所有节点既存放key,又存放数据data,而B+树只有叶节点存放key和value,而内部节点只存放key,b+树每个节点(页),可以存放更多索引(因为没有data占用),故对于大量数据树的高度更低;
叶子节点结构不同:B+树叶子节点间还存在一个链表,方便遍历;
稳定性:因为B+树所有数据都存放在叶子节点,故访问时间稳定,而B树访问过程中可能未到叶子节点就查找到了;
范围查找速率不同:B+树首先遍历树找到下限,再遍历链表找到上限,而B树还需要二分查找。
hash索引
采用hash算法,将key计算得到的hash值,映射到对应的hash表中。
适用于对等比较,= ,in等,不适用于范围查找,因为无序排列。
索引分类
聚簇索引和二级索引
聚簇索引:将数据存储与索引绑定,索引叶节点存放行数据。(必须有且只有一个)
二级索引:数据与索引分开,索引叶节点存放的是主键。(可存在多个)
聚簇索引和非聚簇索引(二级索引)的区别?
- 叶节点存储的数据不同:聚簇索引叶节点存放行数据,而非聚簇索引叶节点存放主键;
- 查询效率不同:因为非聚簇索引还需要返回原表进行二次查询,故查询数据慢;
- 个数限制:聚簇索引一个表只能有一个,而非聚簇索引可以有多个。
回表查询
二级索引查询获取主键后,到聚簇索引中通过主键获取行数据。
索引语法
/*创建索引 */create [unique] index index_name on table_name(字段1,字段2);举例:create index idx_name on emp(name);/*展示索引*/show index from table_name;/*删除索引*/drop index index_name on table_name;举例:drop index username on emp;
查看表增删改查的频次
show global status like 'com_______';
下划线表示模糊匹配。可以查看这个表更新和查询哪个频繁。
show profiles; :查看每条执行语句的耗时情况。
sql性能分析—explain执行计划
在执行语句前加explain可了解语句执行的流程。
/* 例如 */
explain select * from dept , emp where dept.id=emp.id;
id:表示表的执行顺序,值相同表示执行顺序为从上到下,不同则值越大越先执行。
type:表示连接类型,性能由好到差为NULL,system,const,eq_ref,ref,range,index,all。
possible_key:可能应用在这张表上索引。
key:实际用到的索引。
ken_len:索引使用的字节数,越短越好。
extra:额外信息。
索引使用法则-最左前缀法则
如果索引创建在多个字段上,查询时最左字段必须存在,否则索引失效。若跳过中间字段,索引部分失效。
例如我创建name,age,phone三个的联合索引。
/*走部分索引,只有name的索引*/
select * from user where name = '323';
/*走部分索引,只有name的索引,因为跳过了age*/
select * from user where name = '323' and phone = '2323';
/*走部分索引,有name和age的索引*/
select * from user where name = '323' and age = 23;
范围查询(<,>)右侧的列索引失效。
/*走部分索引,有name和age的索引,phone的失效*/
select * from user where name = '323' and age >10 and phone = '22323';
解决方法,用>=,或<=来替换。
不要在索引列上进行运算操作,否则 索引失效。例如:
字符串不加单引号,索引将会失效。
select * from user where name = '323';
/*索引失效*/
select * from user where name = 323;
模糊匹配
如果头部模糊匹配,索引失效。
这样索引不失效。
or连接的索引
如果or条件中有字段有索引,有字段没索引,那么查询不会用到索引。
/*若name或gender其中一个没有添加索引,那么另一个索引不会生效。*/
explain select * from user where name = '小明' and gender = 1;
解决方法:给另一个字段添加索引。
数据分布影响
如果mysql评估走全表扫描比索引快,则不使用索引。
比如用>=,is null等查询大量符合条件的数据。
SQL提示
如果某字段有多个索引,我们可以加入提示达到优化的操作。
user index(index_name):建议使用某个索引。
force index(index_name):强制使用某个索引。
ignore index(index_name):忽略指定索引。
select * from user force index(index_name) where ...
覆盖索引
当一个索引包含了查询所需要的所有字段时,MySQL 就可以直接从该索引中获取所有数据,而不必再回到聚簇索引中进行二次查询。
select id,name,phone from user where name = '小明';
例如在上述中我们可以为name和phone创建联合索引,咋查询时name和phone,id值在二级索引就可以获取到,不需要通过id回表查询。
前缀索引
对于长字符串,或大量文本的字段建立索引时,索引会占用大量空间,为此提出前缀索引,即取前几个字符创建索引,节约索引空间。
语法
create index idx_name on table_name(字段名(n));/*n表示取前n个字符*/
前缀长度:由选择性决定,选择性=不重复索引值 / 数据库表总数。值越高查询效率越好。
索引设计原则
插入数据优化
insert批量插入,避免多次建立连接。
insert into user values(31,'tom',22,1,'113023223'),(34,'hell',22,1,'133238223');
手动开启和关闭事务,避免多次开启和关闭事务。
主键顺序插入
大量插入数据
使用load指令将文本数据插入数据库。
1.连接数据库需要加上参数 --local-infile
mysql --local-infile -u root -p
2.设置全局参数,开启从本地文件导入数据开关。(查询开关,select @@local_infile)
set global local_infile = 1;
3.执行load指令,将准备的数据加载到表结构中
load data local infile '路径/文件名' into table '表名' fields terminated by '字段间的分割符如,' lines terminated by '行之间分隔符如\n';
页分裂
将一条记录插入到已经满的页中时,InnoDB会进行页分裂,即将该记录原本插入位置右边数据移到新页中。
缺点:空间利用率降低,增加了I/O操作。
页合并
当索引页删除记录达到指定比例后,InnoDB会尝试与将当前页与相邻页合并,以提高空间利用率。
主键设计原则
满足业务前提下,尽量降低主键长度。(二级索引的叶节点为主键,占用大量空间)
插入数据,尽量顺序插入,如使用自增主键。(避免出现页分裂)
不要使用UUID或其他自然主键,如身份证号。(字段过长,插入不是有序,出现页分裂)
避免对主键的修改。
order by优化
根据排序字段建立合适索引,多字段排序时,符合最左前缀法则。
尽量使用覆盖索引。
多字段排序, 注意创建联合索引时指定索引创建规则(asc,desc)
group by 优化
分组操作中,也可以为group by后的字段添加索引来提高效率。
分组操作时,索引使用满足最左前缀法则。
limit优化
通过覆盖索引+联表查询方式进行优化。
count优化
count(字段)<count(主键)<count(1)约等于count(*)。
update优化
InnoDB的行锁是对索引加的锁,故对于修改条件的字段可以加索引,这样使用的是行锁,否者为表锁。