建立索引的原则

SQL文件

sql文件下载链接:
https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/world.sql
https://alnk-blog-pictures.oss-cn-shenzhen.aliyuncs.com/blog-pictures/t100w.txt 导入数据库
mysql> source /root/world.sql
mysql> source /root/t100w.txt
说明
为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索引。那么索引设计原则又是怎样的? 设计原则
1 (必须的) 建表时一定要有主键,一般是个无关列 2 选择唯一性索引
唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录 例如,学生表中学号是具有唯一性的字段。为该字段建立唯一性索引可以很快的确定某个学生的信息
如果使用姓名的话,可能存在同名现象,从而降低查询速度 优化方案:
(1) 如果非得使用重复值较多的列作为查询条件(例如:男女),可以将表逻辑拆分
(2) 可以将此列和其他的查询类,做联和索引
select count(*) from world.city;
select count(distinct countrycode) from world.city;
select count(distinct countrycode, population) from world.city; 3(必须的) 为经常需要where 、ORDER BY、GROUP BY、join on等操作的字段建立索引
排序操作会浪费很多时间。
where A B C ----》 A B C
in
where A group by B order by C
A,B,C 如果为其建立索引,优化查询
注:如果经常作为条件的列,重复值特别多,可以建立联合索引 4 尽量使用前缀来索引
如果索引字段的值很长,最好使用值的前缀来索引 5 限制索引的数目
索引的数目不是越多越好。
可能会产生的问题:
(1) 每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。
(2) 修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
(3) 优化器的负担会很重,有可能会影响到优化器的选择.
percona-toolkit中有个工具,专门分析索引是否有用 6 删除不再使用或者很少使用的索引(percona toolkit)
pt-duplicate-key-checker
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理
员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响 7 大表加索引,要在业务不繁忙期间操作 8 尽量少在经常更新值的列上建索引 总结
(1) 必须要有主键,如果没有可以做为主键条件的列,创建无关列
(2) 经常做为where条件列 order by group by join on, distinct 的条件(业务:产品功能+用户行为)
(3) 最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引
(4) 列值长度较长的索引列,我们建议使用前缀索引.
(5) 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit(xxxxx)
(6) 索引维护要避开业务繁忙期

不走索引的情况

没有查询条件,或者查询条件没有建立索引

select * from tab;            全表扫描
select * from tab where 1=1; 全表扫描
在业务数据库中,特别是数据量比较大的表,是没有全表扫描这种需求
1、对用户查看是非常痛苦的
2、对服务器来讲毁灭性的 解决办法
select * from tab;
SQL改写成以下语句:
select * from tab order by price limit 10; # 需要在price列上建立索引 select * from tab where name='zhangsan'; # name列没有索引
改:
1、换成有索引的列作为查询条件
2、将name列建立索引

查询结果集是原表中的大部分数据,应该是25%以上

查询的结果集,超过了总数行数25%,优化器觉得就没有必要走索引了

假如:
tab表有id,name两个字段
id数据:1-100w,id列有(辅助)索引 select * from tab where id>500000;
如果业务允许,可以使用limit控制 结合业务判断,有没有更好的方式。如果没有更好的改写方案
尽量不要在mysql存放这个数据了。放到redis里面。

索引本身失效,统计数据不真实

索引有自我维护的能力
对于表内容变化比较频繁的情况下,有可能会出现索引失效,一般是删除重建索引解决这个问题 现象:
有一条select语句平常查询时很快,突然有一天很慢,会是什么原因
select? --->索引失效,统计数据不真实
DML ? --->锁冲突

查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)

例子:
错误的例子:select * from test where id-1=9;
正确的例子:select * from test where id=10; 算术运算
函数运算
子查询

隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误

这样会导致索引失效. 错误的例子:
mysql> alter table tab add index inx_tel(telnum); mysql> desc tab;
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| telnum | varchar(20) | YES | MUL | NULL | |
+--------+-------------+------+-----+---------+-------+ mysql> select * from tab where telnum='1333333'; 注意这里不是数值,是字符串,要使用单引号
+------+------+---------+
| id | name | telnum |
+------+------+---------+
| 1 | a | 1333333 |
+------+------+---------+ mysql> select * from tab where telnum=1333333; 注意这里不是数值,是字符串,要使用单引号
+------+------+---------+
| id | name | telnum |
+------+------+---------+
| 1 | a | 1333333 |
+------+------+---------+ mysql> explain select * from tab where telnum='1333333'; # 此处使用了单引号,走了索引
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tab | ref | inx_tel | inx_tel | 63 | const | 1 | Using index condition |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+ mysql> explain select * from tab where telnum=1333333; # 此处没有走索引,是全表扫描
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+ mysql> explain select * from tab where telnum=1555555; # 此处没有走索引,是全表扫描
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 2 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+ mysql> explain select * from tab where telnum='1555555'; # 此处使用了单引号,走了索引
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+
| 1 | SIMPLE | tab | ref | inx_tel | inx_tel | 63 | const | 1 | Using index condition |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-----------------------+

<>、not in不走辅助索引

mysql> EXPLAIN  SELECT * FROM tab WHERE telnum  <> '110';  # 不走索引
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 3 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM tab WHERE telnum NOT IN ('110','119'); # 不走索引
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 3 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec) mysql> select * from tab where telnum <> '1555555';
+------+------+---------+
| id | name | telnum |
+------+------+---------+
| 1 | a | 1333333 |
+------+------+---------+ mysql> explain select * from tab where telnum <> '1555555'; # 不走索引
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 3 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec) 单独的 >、<、in、 有可能走,也有可能不走索引,和结果集有关,尽量结合业务添加limit
or或in 尽量改成union
mysql> EXPLAIN SELECT * FROM tab WHERE telnum IN ('110','119'); # 不走索引
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | inx_tel | NULL | NULL | NULL | 3 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 改写成:
mysql> EXPLAIN SELECT * FROM tab WHERE telnum='110'
-> UNION ALL
-> SELECT * FROM tab WHERE telnum='119';
+------+--------------+------------+------+---------------+---------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+------------+------+---------------+---------+---------+-------+------+-------------------------+
| 1 | PRIMARY | tab | ref | inx_tel | inx_tel | 83 | const | 1 | Using index condition |
| 2 | UNION | tab | ref | inx_tel | inx_tel | 83 | const | 1 | Using index condition |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+------+--------------+------------+------+---------------+---------+---------+-------+------+-----------------------+

like "%_" 百分号在最前面不走索引

mysql> EXPLAIN SELECT * FROM tab WHERE telnum LIKE '31%';  # 走range索引扫描
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+
| 1 | SIMPLE | tab | range | inx_tel | inx_tel | 83 | NULL | 1 | Using index condition |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------+ mysql> EXPLAIN SELECT * FROM tab WHERE telnum LIKE '%110'; # 不走索引
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tab | ALL | NULL | NULL | NULL | NULL | 3 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 有类似这种 %131% 的搜索需求,可以使用elasticsearch+mongodb 专门做搜索服务的数据库产品

MySQL-10-索引应用规范的更多相关文章

  1. MySQL开发索引创建规范

    1. [强制]业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引. 说明:不要以为唯一索引影响了insert速度,这个速度损耗可以忽略,但提高查找速度是明显的:另外,即使在应用层做了非 ...

  2. MySQL索引&&开发规范

    规范总结 索引规范 默认添加的索引都是BTree索引.Innodb只支持BTree索引. 设计索引原则 - 最适合索引的列是WHERE子句中的列,而不是SELECT中的列. - 如果索引的字段很长,使 ...

  3. MySql数据库细节使用规范

    一.基础规范 (1)必须使用InnoDB存储引擎 解读:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 (2)必须使用UTF8字符集 解读:万国码,无需转码,无乱码风险,节省 ...

  4. mysql特性及部署规范

    --分支版本,mysql对cpu,内存,io子系统资源利用特点--oracle mysql,mariadb,percona server--部署规范建议,系统安装,mysql安装,其他规范互联网业务为 ...

  5. MySQL 设计与开发规范

    MySQL 设计与开发规范 1 目的 本规范的主要目的是希望规范数据库设计与开发,尽量避免由于数据库设计与开发不当而产生的麻烦:同时好的规范,在执行的时候可以培养出好的习惯,好的习惯是软件质量的很好保 ...

  6. 【夯实Mysql基础】MySQL性能优化的21个最佳实践 和 mysql使用索引

    本文地址 分享提纲: 1.为查询缓存优化你的查询 2. EXPLAIN 你的 SELECT 查询 3. 当只要一行数据时使用 LIMIT 1 4. 为搜索字段建索引 5. 在Join表的时候使用相当类 ...

  7. MySQL中索引和优化的用法总结

    1.什么是数据库中的索引?索引有什么作用? 引入索引的目的是为了加快查询速度.如果数据量很大,大的查询要从硬盘加载数据到内存当中. 2.InnoDB中的索引原理是怎么样的? InnoDB是Mysql的 ...

  8. MySQL 联合索引详解

    MySQL 联合索引详解   联合索引又叫复合索引.对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分.例如索引是key index (a,b,c ...

  9. 如何正确建立MYSQL数据库索引

    索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型. 在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytabl ...

  10. MySQL 运行环境建议规范

    一.操作系统环境 操作系统版本选择 CentOS/RHRL/ORACLE Linux 5.x/6.x x86_64 发行版 建议磁盘分区规则 MySQL 运行环境建议规范 挂载点 大小 分区类型 分区 ...

随机推荐

  1. RabbitMQ消息可靠性传输

    消息的可靠性投递是使用消息中间件不可避免的问题,不管是使用kafka.rocketMQ或者rabbitMQ,那么在RabbitMQ中如何保证消息的可靠性投递呢? 先再看一下RabbitMQ消息传递的流 ...

  2. Docker:Linux离线安装docker

    docker离线下载路径 docker所有版本:https://download.docker.com/linux/static/stable/ 离线安装 1.解压 #解压tar包 tar -xvf ...

  3. springboot整合拦截器如何让其不拦截默认的访问路径

    1.注册自定义拦截器2.拦截器3.控制器4.其它说明:我想做控制拦截登陆,将所有的请求拦截下来判断如果当前的session里没有用户名则跳转到登陆页面.问题是目前可以拦截所有请求了,但第一次进入登陆页 ...

  4. ESP32-mqtt笔记

    基于ESP-IDF4.1 #include <stdio.h> #include <stdint.h> #include <stddef.h> #include & ...

  5. C#版Nebula客户端编译

    一.需求背景 从Nebula的Github上可以发现,Nebula为以下语言提供了客户端SDK: nebula-cpp nebula-java nebula-go nebula-python nebu ...

  6. Django基础011-form&modelform

    1.form from django import forms from django.core.exceptions import ValidationError #出现异常时用的 from use ...

  7. 一行代码打印python之禅

    就这一句: import this 输出: The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is be ...

  8. c++中的对象模型

    1 对象模型的前世 类在c++编译器内部可以理解成结构体,所以在对象模型分析时,我们可以把 class  当作一种特殊的 struct: 1)在内存中 class 可以看作是普通成员变量的集合: 2) ...

  9. Hive——基本DML语句

    Hive--基本DML语句 DML:Data Manipulation Language(数据操作语言,与关系型数据库相似) 官方手册:https://cwiki.apache.org/conflue ...

  10. springboot-8-企业开发

    一.邮件发送 流程: mbqplwpheeyvgdjh 首先需要开启POS3/SMTP服务,这是一个邮件传输协议 点击开启 导入依赖 <!--mail--> <dependency& ...