【转】Mysql索引设计原则
来源:https://segmentfault.com/a/1190000000473085
假设一高频查询如下
SELECT * FROM user WHERE area='amoy' AND sex=0 ORDER BY last_login DESC limit 30;
如何建立索引?描述考虑的过程
user表如下:
初始化100W条数据,其中,area要通过IP查询生成,sex为 0,1 随机
CREATE TABLE user (id int(10) NOT NULL AUTO_INCREMENT COMMENT '自增编号',username varchar(30) NOT NULL DEFAULT '0' COMMENT '用户名',password varchar(30) NOT NULL DEFAULT '0' COMMENT '密码',area varchar(30) NOT NULL COMMENT '地址',sex int(10) NOT NULL COMMENT '性别1,男;2,女。',last_login int(10) NOT NULL COMMENT '最近一次登录时间戳',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=892013 DEFAULT CHARSET=latin1
最终我的索引
(last_login,area)
索引原则:
1.where和order by等的字段建立索引
2.使用唯一索引:对于last_login,area等字段重复的次数比较少,可以使用索引;而sex无非就两个值:性别1,男;2,不值得索引
3.多列索引:不要为每一个列单独建立索引,这样并不能将mysql索引的效率最大化。使用“索引合并策略”
4.选择合理的索引列顺序:索引列的顺序意味着索引首先按照最左列进行排序,然后是第二列,以此类推。如(last_login,area)会先按照 last_login 进行排序,然后才是area。
5.将选择性最高的索引放到前面,也就是会所按照这个条件搜索到的数据最少,选择性就越高,比如选择性:last_login> area> sex。
6.索引不是越多越好,适合的索引可以提高查询效率,但是会降低写入效率,根据项目保持两者的平衡性最好了。
总结上面,首先sex不适合建立索引,有没有索引对于效率的提升意义不大,其次索引会按照最左列进行排序,因此将last_login放到最前面。
测试过程:
user表
没有任何索引的查询相关日志:
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.56s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.55s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.59s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.55s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.55s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.58s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
共花费时间:5.66s
建立索引area:
ALTER TABLE user ADD INDEX index_area (area) ;
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.10s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.11s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.20s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.07s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
共花费时间:0.66s
可见,建立area以后对性能的影响是巨大的(5.66/0.66 约为8.5758倍)
删除索引:ALTER TABLE user DROP INDEX index_area;
删除area索引发现时间又变成了0.57s
建立last_login索引:
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.09s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.51s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.07s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
共花费时间:0.87s
同样能够提升性能(5.66/0.87 约为6.5057倍)
建立sex索引:
ALTER TABLE user ADD INDEX index_sex (sex) ;
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.89s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.88s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.86s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.88s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
共花费时间:8.73s
同样能够提升性能(5.66s/8.73 约为0.6483倍)效率反而降低了??求解?
建立这个sex索引还不如不建。
删除索引:
ALTER TABLE user DROP INDEX index_sex;
发现时间又变成了0.57s左右,
建立两个单独的索引:
ALTER TABLE user
ADD INDEX index_area (area) ,
ADD INDEX index_last_login (last_login) ;
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.09s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.33s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.21s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.28s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.67s
发现建立两个单独的索引还不如只建立一个索引
删除索引:
发现时间又变成了0.57s左右,
建立一个的联合索引:
ALTER TABLE user
ADD INDEX index_last_login_area (last_login,area) ,
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
额,第二条数据这是怎么了,我测试了5次都在这附近晃悠哈!
这尼玛,找对索引啦!就该这么建立,查询不出来需要的时间啦!估计就是我们需要的索引啦!!!!
删除索引:
发现时间又变成了0.57s左右,
建立一个的联合索引:
ALTER TABLE user
ADD INDEX index_sex_last_login_area (sex,last_login,area)
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.18s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.17s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.81s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
sex怎么总是你在拖后腿啊!把你调整到索引的最后一个吧!
删除索引:
发现时间又变成了0.57s左右,
建立一个的联合索引:
ALTER TABLE user
ADD INDEX index_last_login_area_sex (area,last_login,sex)
SELECT * FROM user WHERE area='美国ATT用户' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='泰国' AND sex=0 ORDER BY last_login DESC limit 30; 0.07s
SELECT * FROM user WHERE area='台湾省台湾大宽频' AND sex=0 ORDER BY last_login DESC limit 30; 0.50s
SELECT * FROM user WHERE area='美国弗吉尼亚州' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='德国奔驰汽车' AND sex=0 ORDER BY last_login DESC limit 30; 0.05s
SELECT * FROM user WHERE area='台湾省中华电信' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
SELECT * FROM user WHERE area='韩国' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='拉美地区' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='美国纽约(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='印度尼西亚' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
综上所述:1.建立索引不一定能够加快查询效率如sex这种给重复次数特别多的列增加索引如sex这种会降低查询效率,具体的原因有待查找
2.给重复次数比较少的列增加u讴吟还是能够大幅度提高效率
3.给where和orderby之后的字段添加索引才会加快查询效率
4.为每一个列单独建立索引,不能将索引的效率最大化,应该使用索引合并策略,即根据查询条件,建立联合索引
5.联合索引的顺序问题:将选择性高的索引放到前面
6.根据资料建立索引意味着索引按照最左列进行排序,然后事第二列,以此类推。如(last_login ,area)就会按照last_login进行排序,然后才是area
7.根据这次的这个查询条件来说最好的索引是:ALTER TABLE userADD INDEX index_last_login_area (last_login,area)。
【转】Mysql索引设计原则的更多相关文章
- MySQL三层结构、用户权限、索引设计原则
一.守护进程是什么? Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对 ...
- mysql的索引设计原则以及常见索引的区别
索引定义:是一个单独的,存储在磁盘上的数据库结构,其包含着对数据表里所有记录的引用指针. 数据库索引的设计原则: 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索引和创建什么类型的索 ...
- MySql 表索引设计原则
索引的优点 1.加快数据的检索速度,这是创建索引的最主要的原因; 2.通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性; 3.加速表和表之间的连接; 4.在使用分组和排序子句进行数据检索时,可 ...
- Mysql高级操作学习笔记:索引结构、树的区别、索引优缺点、创建索引原则(我们对哪种数据创建索引)、索引分类、Sql性能分析、索引使用、索引失效、索引设计原则
Mysql高级操作 索引概述: 索引是高效获取数据的数据结构 索引结构: B+Tree() Hash(不支持范围查询,精准匹配效率极高) 树的区别: 二叉树:可能产生不平衡,顺序数据可能会出现链表结构 ...
- MySQL索引设计需要考虑哪些因素?
索引小知识 篇幅有限,索引的基本知识我们就不赘述了,在此,我们尝试说明其中的一个小点-----B+树与B树的区别到底是什么. InnoDB是使用B+树来实现其索引功能的.在B+树中,内节点(非叶子节点 ...
- mySql 数据库设计原则
mysql数据库设计原则: 必须使用InnoDB存储引擎 解读:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 禁止使用存储过程.视图.触发器.Event 解读:高并发大数据 ...
- mysql索引设计的注意事项
mysql索引设计的注意事项 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过key_len确定究竟使用 ...
- mysql索引设计的注意事项(大量示例,收藏再看)
mysql索引设计的注意事项(大量示例,收藏再看) 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过ke ...
- Sql Server系列:索引设计原则及优化
1. 索引设计原则 索引设计不合理或缺少索引都会对数据库的性能造成障碍,高效的索引对于获得良好的性能非常重要. 设计索引时的一些原则: ◊ 索引并不是越多越好,一个表中如果有大量的索引,不仅占用大量的 ...
随机推荐
- 利用Django实现webUI展示
1.说明 最近老大想要做一个webUI界面,为了展示我们数据中心工作内容,需要把各自的工作内容用webUI展示出来.目前我负责的做公司名称归一化的问题. 2.Django实现web 具体实现是完全按照 ...
- Unix代码分析
世存最早的unix源代码:http://minnie.tuhs.org/cgi-bin/utree.pl?file=PDP7-Unix/sys 世存最早的cc:http://minnie.tuhs.o ...
- [C++]几种排序
本文为大大维原创,最早于博客园发表,转载请注明出处!!! 1.冒泡: #include<cmath> #include<cstdlib> #include<ctime&g ...
- python实际练习1——简单购物车
要求实现 启动程序后,让用户输入工资,然后打印商品列表 允许用户根据商品编号购买商品 用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 可随时退出,退出时,打印已购买商品和余额 自己写的代码是 ...
- re正则表达式匹配字符串中的数字
re.match(r'.*-(\d*).html',url_1).group(1) \d+匹配1次或者多次数字,注意这里不要写成*,因为即便是小数,小数点之前也得有一个数字:\.?这个是匹配小数点的, ...
- Mysql 大量Sleep 解决
排查 SHOW GLOBAL VARIABLES LIKE 'wait_timeout'; SHOW GLOBAL VARIABLES LIKE 'interactive_timeout'; 在线更新 ...
- ES6 —— 数组总结
1. map:映射 一个对一个 arr.map(function(item) { ... }) 可以配合箭头函数:arr.map(item => ... ) let arr1 = [1 ...
- WEB学习笔记11-高可读性的HTML之如何设置网页标题层级
标题标签指的是<h1>~<h6>这6个标签,统称为<hx>标签. (1)在页面内容的标题部分使用<hx>标签 <h1 class="re ...
- 开发Canvas 绘画应用(二):实现绘画
开发Canvas 绘画应用(一):搭好框架 中我们已经把基本框架及基础功能实现了,现在要实现本应用的重点:绘画功能. 首先分析一下,我们要实现绘画,需要具备的理论知识如下: (1)获取触摸点的坐标 类 ...
- hdu 1372 BFS
A friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the sh ...