建立索引的原则

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. Linux安全攻防:使用TRAP实现持续控制和提权

    ATT&CK TRAP技术说明 在ATT&CK中,TRAP属于事件触发执行的一种技术,可以用于持续控制(persistence)和提权(privilege escalation). T ...

  2. log4j和log4j2的配置部分

    log4j和log4j2的功能及形式对比 http://blog.csdn.net/fangaohua200/article/details/53561718 log4j2的proptise配置 ht ...

  3. MySQL索引类型总结和使用技巧以及注意事项 (转)

      在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytable表:  代码如下: CREATE TABLE mytable(   ID INT NOT NULL,    us ...

  4. Linux | 搜索命令

    grep grep 命令用于在文本中执行关键词搜索,并显示匹配的结果,格式:grep[选项][文本] grep命令的参数及其作用 参数 作用 -b 将可执行文件当作文本文件对待 -c 公显示找到的行数 ...

  5. C语言:强制类型转换

    #include <stdio.h> //强制类型转换 //写法:(类型标识符)变量:(类型标识符)常量:(类型标识符)(表达式):三种格式 main() { float a=7.5f; ...

  6. 高校表白App-团队冲刺第三天

    今天要做什么 今天开站立会议的时候,忽然发觉在一个完整的App上好像是有一些引导页的,比如说在第一次使用App的时候,或者是在使用App的时候会出现新手指引操作. 做了什么 通过查阅资料来学习View ...

  7. modelsim 独立仿真vivado的IP核及仿真脚本

    Modelsim独立仿真vivado的IP 最近一直在做local dimming项目的FPGA硬件实现,算法的其中一步就是直方图统计,即数字图像的某一灰度级的像素数,这个直方图的源码找了半天才搞到, ...

  8. 软件开发(js+java开发)的启发

    发现了个很重要的意义 1,一个对象,既包含被监听的参数,也包括监听处理本身 2,基于1的开发模式 3,在函数中定义监听器 4,1)高内聚: 统一面向对象,一个功能一个对象 不同对象不互相调用,不互相引 ...

  9. python + Excel数据读取(更新)

    data.xlsx 数据如下: import xlrd#1.读取Excel数据# table = xlrd.open_workbook("data.xlsx","r&qu ...

  10. python + mysql 实现查询表数据

    实例如下: import pymysqldef select_form(): # 打开数据库连接 db = pymysql.connect("localhost", "r ...