索引html
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里全部记录的引用指针。更通俗的说,数据库索引比如是一本书前面的目录,能加快数据库的查询速度。对于一个SQL语句,在没有索引的状况下,数据库会遍历所有数据后选择符合条件的;而有了相应的索引以后,数据库会直接在索引中查找符合条件的选项。node
总之:索引是为了优化查询,而select 查询有三种状况:缓存查询(不在mysql中进行数据查询),全表扫描,索引扫描mysql
索引的种类redis
Mysql目前主要有如下几种索引类型:FULLTEXT,HASH,BTREE,RTREE。算法
FULLTEXTsql
即为全文索引,目前只有MyISAM引擎支持。数据库
全文索引并非和MyISAM一块儿诞生的,它的出现是为了解决WHERE name LIKE “%word%"这类针对文本的模糊查询效率较低的问题。vim
HASH缓存
因为HASH的惟一(几乎100%的惟一)及相似键值对的形式,很适合做为索引。bash
HASH索引能够一次定位,不须要像树形索引那样逐层查找,所以具备极高的效率。可是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。
BTREE(btree b+tree b*tree)
BTREE索引就是一种将索引值按必定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最经常使用的索引类型。
RTREE
RTREE在MySQL不多使用,仅支持geometry数据类型,支持该类型的存储引擎只有MyISAM、BDb、InnoDb、NDb、Archive几种。
相对于BTREE,RTREE的优点在于范围查找。
Btree索引分类
汇集索引:基于主键,自动生成的,通常是建表时建立主键.若是没有主键,自动选择惟一键作为汇集索引.
辅助索引:人为建立的(普通索引,覆盖索引)
惟一索引:人为建立(普通索引,汇集索引)
执行计划
见http://www.javashuo.com/article/p-mqinpdcx-cp.html
运维规范
1、数据库索引的设计原则:
为了使索引的使用效率更高,在建立索引时,必须考虑在哪些字段上建立索引和建立什么类型的索引。
那么索引设计原则又是怎样的?
0.建表时必定要有主键,若是不相关列能够做为主键,作一个无关列
1.选择惟一性索引
惟一性索引的值是惟一的,能够更快速的经过该索引来肯定某条记录。
例如,学生表中学号是具备惟一性的字段。为该字段创建惟一性索引能够很快的肯定某个学生的信息。
若是使用姓名的话,可能存在同名现象,从而下降查询速度。
主键索引和惟一键索引,在查询中使用是效率最高的。
select count(*) from world.city;
select count(distinct countrycode) from world.city;
select count(distinct countrycode,population ) from world.city;
注意:若是重复值较多,能够考虑采用联合索引
2.为常常须要排序、分组和联合操做的字段创建索引
常常须要ORDER BY、GROUP BY,join on等操做的字段,排序操做会浪费不少时间。
若是为其创建索引,能够有效地避免排序操做。
3.为常做为where查询条件的字段创建索引
若是某个字段常常用来作查询条件,那么该字段的查询速度会影响整个表的查询速度。所以,
为这样的字段创建索引,能够提升整个表的查询速度。
3.1 常常查询
3.2 列值的重复值少(业务层面调整)
注:若是常常做为条件的列,重复值特别多,能够创建联合索引。
4.尽可能使用前缀来索引
若是索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索
会很浪费时间。若是只检索字段的前面的若干个字符,这样能够提升检索速度。
------------------------以上的是重点关注的,如下是能保证则保证的--------------------
5.限制索引的数目
索引的数目不是越多越好。每一个索引都须要占用磁盘空间,索引越多,须要的磁盘空间就越大。
修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。
6.删除再也不使用或者不多使用的索引(percona toolkit)
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能再也不须要。数据库管理
员应当按期找出这些索引,将它们删除,从而减小索引对更新操做的影响。
7.大表加索引,要在业务不繁忙期间操做
总结
(1) 必需要有主键,若是没有能够作为主键条件的列,建立无关列
(2) 常常作为where条件列 order by group by join on的条件(业务:产品功能+用户行为)
(3) 最好使用惟一值多的列做为索引,若是索引列重复值较多,能够考虑使用联合索引
(4) 列值长度较长的索引列,咱们建议使用前缀索引.
(5) 下降索引条目,一方面不要建立没用索引,不常使用的索引清理,percona toolkit
(6) 索引维护要避开业务繁忙期
不走索引的状况(开发规范)
1) 没有查询条件,或者查询条件没有创建索引
select * from tab; 全表扫描。
在业务数据库中,特别是数据量比较大的表。
是没有全表扫描这种需求。
一、对用户查看是很是痛苦的。
二、对服务器来说毁灭性的。
(1)select * from tab; SQL改写成如下语句: selec * from tab order by price limit 10 须要在price列上创建索引 (2)select * from tab where name='zhangsan' name列没有索引 改: 1、换成有索引的列做为查询条件 二、将name列创建索引
2) 查询结果集是原表中的大部分数据,应该是25%以上。
查询的结果集,超过了总数行数25%,优化器以为就没有必要走索引了。 假如:tab表 id,name id:1-100w ,id列有索引 select * from tab where id>500000; 若是业务容许,可使用limit控制。 怎么改写 ? 结合业务判断,有没有更好的方式。若是没有更好的改写方案 尽可能不要在mysql存放这个数据了。放到redis里面。
3) 索引自己失效,统计数据不真实
索引有自我维护的能力。
对于表内容变化比较频繁的状况下,有可能会出现索引失效。
4) 查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)
例子:
错误的例子:select * from test where id-1=9;
正确的例子:select * from test where id=10;
算术运算
函数运算
desc select * from blog_userinfo where DATE_FORMAT(last_login,'%Y-%m-%d') >= '2019-01-01';
子查询
5)隐式转换致使索引失效.这一点应当引发重视.也是开发中常常会犯的错误.
select * from t1 where telnum=110;
6) <> ,not in 不走索引
7) like "%_" 百分号在最前面不走
8) 单独引用联合索引里非第一位置的索引列.做为条件查询时不走索引.
CREATE TABLE t1 (id INT,NAME VARCHAR(20),age INT ,sex ENUM('m','f'),money INT); ALTER TABLE t1 ADD INDEX t1_idx(money,age,sex); 走索引的状况测试: EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 AND sex='m'; EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND age=30 ; EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE money=30 AND sex='m'; ----->部分走索引 不走索引的: EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=20 EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE age=30 AND sex='m'; EXPLAIN SELECT NAME,age,sex,money FROM t1 WHERE sex='m';
压力测试
1、模拟数据库数据 为了测试咱们建立一个oldboy的库建立一个t1的表,而后导入50万行数据,脚本以下: vim slap.sh #!/bin/bash HOSTNAME="localhost" PORT="3306" USERNAME="root" PASSWORD="123" DBNAME="oldboy" TABLENAME="t1" #create database mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "drop database if exists ${DBNAME}" create_db_sql="create database if not exists ${DBNAME}" mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} -e "${create_db_sql}" #create table create_table_sql="create table if not exists ${TABLENAME}(stuid int not null primary key,stuname varchar(20) not null,stusex char(1) not null,cardid varchar(20) not null,birthday datetime,entertime datetime,address varchar(100)default null)" mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${create_table_sql}" #insert data to table i="1" while [ $i -le 500000 ] do insert_sql="insert into ${TABLENAME} values($i,'alexsb_$i','1','110011198809163418','1990-05-16','2017-09-13','oldboyedu')" mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${insert_sql}" let i++ done #select data select_sql="select count(*) from ${TABLENAME}" mysql -h ${HOSTNAME} -P${PORT} -u${USERNAME} -p${PASSWORD} ${DBNAME} -e "${select_sql}" 执行脚本: sh slap.sh 2、检查数据可用性 mysql -uroot -p123 select count(*) from oldboy.t1; 3、在没有优化以前咱们使用mysqlslap来进行压力测试 # 100个线程,总共2000个请求 mysqlslap --defaults-file=/etc/my.cnf \ --concurrency=100 --iterations=1 --create-schema='oldboy' \ --query="select * from oldboy.t1 where stuname='alexsb_100'" engine=innodb \ --number-of-queries=2000 -uroot -p123 -verbose