一文带你了解Sql优化

我们后台开发人员每天都难免与数据库打交道,那么你在写sql语句的时候有注重到自己sql的效率吗?当你sql查询速度很慢的时候你有想过是你的sql语句造成的吗?看完这篇文章,我相信你会对sql优化有了一定的了解!

explain

通过查看sql执行计划来确定各部位的问题。使用方法:在sql语句前面加上explain关键字。

1
explain SELECT * FROM (SELECT id FROM sys_address where remarks='中国' or remarks='中国重庆'  or remarks='中国重庆重庆市' or remarks like '%渝北区%') a

执行结果:

id select_type table partitions type possible_keys key key_len ref rows filtered Extr
1 SIMPLE sys_address ALL 667651 35.2 Using where

参数说明:

  • id

id值越大,优先级越高,就越先执行。如果id值一样,那可以看成一组。

  • select_type

常见的值以及含义:

SIMPLE 简单的select查询,查询中不包含子查询或者UNION。

PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为PRIMARY。

SUBQUERY 在SELECT或WHERE列表中包含了子查询。

DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生),MySQL会递归执行这些子查询,把结果放在临时表中。

UNION 若第二个SELECT出现在UNION之后,则被标记为UNION:若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED。

UNION RESULT 从UNION表获取结果的SELECT。

  • table

值就是当前执行的表名。

  • partitions
  • type

执行效率 system > const > eq_ref > ref > range > index > all

system:表仅有一行(=系统表)。这是const联接类型的一个特例。

const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。

const用于用常数值比较PRIMARY KEY或UNIQUE索引的所有部分时。

eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引

的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或

一个使用在该表前面所读取的表的列的表达式。

ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如

果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量

行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列。

ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的

优化。

index_merge:该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使

用的索引的最长的关键元素。

unique_subquery:该类型替换了下面形式的IN子查询的ref:value IN (SELECT primary_key FROMsingle_table WHERE

some_expr);unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。

index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:

value IN (SELECT key_column FROM single_table WHERE some_expr)

range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。

在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,

可以使用range。

  • possible_keys

possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着

在possible_keys中的某些键实际上不能按生成的表次序使用。

  • key

key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的

索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

  • key_len

key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使

用一个多部关键字的几个部分。

  • ref

ref列显示使用哪个列或常数与key一起从表中选择行。

  • rows

rows列显示MySQL认为它执行查询时必须检查的行数。

  • filtered
  • Extr

该列包含MySQL解决查询的详细信息。

Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。

Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检

查更多的行。

range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已

知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行。

Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配

WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。

Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为单一索引一

部分的列时,可以使用该策略。

Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的

GROUP BY和ORDER BY子句时。

Using where:WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值

不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。

Using sort_union(…), Using union(…), Using intersect(…):这些函数说明如何为index_merge联接类型合并索引扫描。

Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可

以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于

每个组,只读取少量索引条目。

索引

索引的作用就是加快查询速度,它就像书的目录,当你想获取到里面内容位置时,就需要可以通过目录快速的定位到具体位置。

首先我们需要明确一点,索引并不是越多越好。因为写入数据时,会对索引字段进行一些处理,就会影响插入速度。

在MySql中的常用索引:

  • 主键索引

一个表中只有一个主键索引,一般在建表的时候就自动存在了。由系统自动创建,不需要额外手动创建。

  • 普通索引

一般索引。

1
ALTER TABLE table_name ADD INDEX 索引名(column1,column2);
  • 唯一索引

表示列中不能有重复值。

1
ALTER TABLE `table_name` ADD UNIQUE (`column`);
  • 全文索引

通常用于文本值中,比如商品详细信息等。

合理添加索引

  1. 查询频繁的字段,应该添加索引。
  2. 更新频繁的字段,不应该添加索引。
  3. 唯一性太差的字段不应该添加索引,比如sex性别字段。

索引失效

以下几种情况,即使字段创建了索引,也不会使用到。

  1. like语句以“%”开头。
  2. or语句的字段没有全部使用索引,其中任意一个没有索引的话,此条件就不会使用索引。
  3. 在组合查询中,第一个查询字段的名称不是复合索引中的第一列。
  4. 在索引列上使用IS NULL 或者IS NOT NULL,索引是不能索引空值的,这样的操作会导致全表扫描。
  5. 在索引字段上使用not 、<>、!=。
  6. 在索引字段上执行函数,如DATE_FORMAT(data, format)。
查看评论