M ysql索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不是越多越好,假如这本书1000页,有500也是目录,它当然效率低,目录是要占纸张的,而索引是要占磁盘空间的。
Mysql常见索引有:主键索引、唯一索引、普通索引、全文索引、组合索引
PRIMARY KEY(主键索引)
CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) )
ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )
UNIQUE(唯一索引)
CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表)
ALTER TABLE `table_name` ADD UNIQUE (`column`)
INDEX(普通索引)
创建索引,CREATE INDEX <索引的名字> ON tablename (列的列表);
修改索引,ALTER TABLE `table_name` ADD INDEX index_name ( `column` )
创建表的时候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) )
FULLTEXT(全文索引)
ALTER TABLE `table_name` ADD FULLTEXT ( `column` )
组合索引
ALTER TABLE `table_name` ADD INDEX index_name ( `column1`,`column2`, `column3` )
Mysql各种索引区别:
普通索引:最基本的索引,没有任何限制。
唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
主键索引:它是一种特殊的唯一索引,不允许有空值。
全文索引:仅可用于MyISAM表,针对较大的数据,生成全文索引很耗时好空间。
组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。
讲下你项目里做的数据库索引优化,如何去分析一条语句的执行性能,explain语句你会关注哪些字段
索引优化策略:
*最左前缀匹配原则,上面讲到了
*主键外检一定要建索引
*对 where,on,group by,order by 中出现的列使用索引
*尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0。对较小的数据列使用索引,这样会使索引文件更小,同时内存中也可以装载更多的索引键
*索引列不能参与计算,保持列“干净”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);
*为较长的字符串使用前缀索引
*尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可,不要过多创建索引, 权衡索引个数与DML之间关系,DML也就是插入、删除数据操作。这里需要权衡一个问题,建立索引的目的是为了提高查询效率的,但建立的索引过多,会影响插入、删除数据的速度,因为我们修改的表数据,索引也需要进行调整重建
*对于like查询,”%”不要放在前面。
SELECT * FROM houdunwang WHERE uname LIKE '后盾%' -- 走索引
SELECT *FROM houdunwang WHERE uname LIKE '%后盾%' -- 不走索引
*查询where条件数据类型不匹配也无法使用索引
*字符串与数字比较不使用索引;
CREATE TABLE a(a char(10));
EXPLAIN SELECT * FROM a WHERE a="1" – 走索引
EXPLAIN SELECT * FROM a WHERE a=1 – 不走索引
正则表达式不使用索引,这应该很好理解,所以为什么在SQL中很难看到regexp关键字的原因
Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。
Explain语法:
EXPLAIN
tbl_name或:EXPLAIN[EXTENDED] SELECT select_options
前者可以得出一个表的字段结构等等,后者主要是给出相关的一些索引信息,而今天要讲述的重点是后者。
例如:
EXPLAIN
SELECT sum(amount)
FROM customer a, payment b
WHERE1 = 1
AND a.customer_id = b.customer_id
AND a.email = 'JANE.BENNETT@sakilacustomer.org';
执行结果:
下面对各个属性进行了解:
1、id:这是SELECT的查询序列号。每个 SELECT 都会自动分配一个唯一的标识符。
2、select_type:select_type就是select的类型,可以有以下几种:
SIMPLE:简单SELECT(不使用UNION或子查询等)
PRIMARY:最外面的SELECT
UNION:UNION中的第二个或后面的SELECT语句
DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT:UNION的结果。
SUBQUERY:子查询中的第一个SELECT
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
DERIVED:导出表的SELECT(FROM子句的子查询)
3、table:显示这一行的数据是关于哪张表的实际的表名(如select * from customer;) 或表的别名 (如 select * from customer a);
4、type:这列最重要,显示了连接使用了哪种类别,有无使用索引,是使用Explain命令分析性能瓶颈的关键项之一。通过 type 字段, 我们判断此次查询是 全表扫描 还是 索引扫描等。
system > const > eq_ref > ref > fulltext >ref_or_null > index_merge > unique_subquery > index_subquery >range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。
● all: 意味着从表的第1行,往后逐行做全表扫描,运气不好扫描到最后一行。
● index:表示全索引扫描(full index scan),和 ALL 类型类似,只不过 ALL 类型是全表扫描, 而 index 类型则仅仅扫描所有的索引, 而不扫描数据。比all性能稍好一点,通俗的说: all 扫描所有的数据行,相当于data_all index 扫描所有的索引节点,相当于index_all。注:all是沿着磁盘扫描,index是沿着索引扫描。例如:EXPLAIN SELECT name FROM user_info。上面的例子中, 我们查询的 name 字段恰好是一个索引, 因此我们直接从索引中获取数据就可以满足查询的需求了, 而不需要查询表中的数据. 因此这样的情况下, type 的值是 index, 并且 Extra 的值是Using Index。
● range: 意思是查询时,能根据索引做范围的扫描。表示使用索引范围查询,通过索引字段范围获取表中部分数据记录。这个类型通常出现在 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操作中。当 type 是 range 时, 那么 EXPLAIN 输出的 ref 字段为 NULL, 并且 key_len 字段是此次查询中使用到的索引的最长的那个。例如,EXPLAIN SELECT * FROM user_info WHERE id BETWEEN 2 AND 8。
● index_subquery 在子查询中,基于除唯一索引之外的索引进行扫描;
● unique_subquery在子查询中,基于唯一索引进行扫描,类似于EQ_REF;
● index_merge 多重范围扫描。两表连接的每个表的连接字段上均有索引存在且索引有序,结果合并在一起。适用于作集合的并、交操作。
● ref_or_null 类似REF,只是搜索条件包括:连接字段的值可以为NULL的情况,比如where col = 2 or col is null
● fulltext 全文索引
● ref 此类型通常出现在多表的 join 查询。针对于非唯一或非主键索引,或者是使用了最左前缀 规则索引的查询(也是范围区间,不过比range更加精确)。例如,EXPLAIN SELECT * FROM user_info, order_info WHERE user_info.id = order_info.user_id AND order_info.user_id = 5。
● eq_ref是指通过索引列,直接引用某1行数据(精确到一行数据中)常见于连接查询中,表示对于前表的每一个结果,都只能匹配到后表的一行结果。并且查询的比较操作通常是 =,查询效率较高。例如,EXPLAIN SELECT * FROM user_info,order_info WHERE user_info.id = order_info.user_id。
● const, system, null 当mysql能对查询的部分就行优化,并且转换成一个常量的时候,它就会使用这种访问类型了。比如你把一行的主键当做where条件放进去,那mysql就可以把它转换成一个常量,然后查询。例如,explain select * from user_info where id = 2。
5、possible_keys:列指出MySQL能使用哪个索引在该表中找到行
6、key:此字段是 MySQL 在当前查询时所真正使用到的索引。如果没有选择索引,键是NULL。
7、key_len:显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好
8、ref:显示使用哪个列或常数与key一起从表中选择行。
9、rows:显示MySQL认为它执行查询时必须检查的行数。rows 也是一个重要的字段。
MySQL查询优化器根据统计信息, 估算 SQL 要查找到结果集需要扫描读取的数据行数。这个值非常直观显示 SQL 的效率好坏, 原则上 rows 越少越好。
10、Extra:包含MySQL解决查询的详细信息,也是关键参考项之一。