数据库优化总结

Posted 软件技术共享平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库优化总结相关的知识,希望对你有一定的参考价值。

第一部分:SQL语句优化

1、尽量避免使用select *,使用具体的字段代替*,只返回使用到的字段。

2、尽量避免使用in 和not in,会导致数据库引擎放弃索引进行全表扫描。

SELECT * FROM t WHERE id IN (2,3)SELECT * FROM t1 WHERE username IN (SELECT username FROM t2)

优化方式:如果是连续数值,可以用between代替。如下:

SELECT * FROM t WHERE id BETWEEN 2 AND 3

如果是子查询,可以用exists代替。如下:

SELECT * FROM t1 WHERE EXISTS (SELECT * FROM t2 WHERE t1.username = t2.username)

3、尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。如下:

SELECT * FROM t WHERE username LIKE '%li%'

优化方式:尽量在字段后面使用模糊查询。如下:

SELECT * FROM t WHERE username LIKE 'li%'

4、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。如下:

SELECT * FROM t WHERE score IS NULL

优化方式:可以给字段添加默认值0,对0值进行判断。如下:

SELECT * FROM t WHERE score = 0

5、尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。如下:

SELECT * FROM t2 WHERE score/10 = 9SELECT * FROM t2 WHERE SUBSTR(username,1,2) = 'li'

优化方式:可以将表达式、函数操作移动到等号右侧。如下:

SELECT * FROM t2 WHERE score = 10*9SELECT * FROM t2 WHERE username LIKE 'li%'

6.当只要一行数据时使用LIMIT 1

加上LIMIT 1可以增加性能。mysql数据库引擎会在查找到一条数据后停止搜索,而不是继续往后查询下一条符合条件的数据记录

7、使用连接(JOIN)来代替子查询(Sub-Queries)

8、在建有索引的字段上尽量不要使用函数进行操作

例如,在一个DATE类型的字段上使用YEAE()函数时,将会使索引不能发挥应有的作用。

9、排序的索引问题

mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

10、应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。

11、应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:

select id from t where num=10 or Name = 'admin'

可以这样查询:

select id from t where num = 10union allselect id from t where Name = 'admin'


12、索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。

比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。


第二部分:数据库索引


1、索引的创建、查看、删除


//创建索引有两种方式:1.CREATE TABLE语句时可以创建索引 2.单独用CREATE INDEXALTER TABLE来为表增加索引// 1ALTER TABLE 用来创建普通索引、唯一索引、主键索引和全文索引ALTER TABLE table_name ADD INDEX index_name (column_list);ALTER TABLE table_name ADD UNIQUE (column_list);ALTER TABLE table_name ADD PRIMARY KEY (column_list);ALTER TABLE table_name ADD FULLTEXT (column_list);
// 2、CREATE INDEX可对表增加普通索引或UNIQUE索引以及全文索引,但是不可以对表增加主键索引CREATE INDEX index_name ON table_name (column_list);CREATE UNIQUE index_name ON table_name (column_list);CREATE FULLTEXT index_name ON table_name (column_list);


查看索引mysql> show index from tblname;mysql> show keys from tblname;

删除索引删除索引的mysql格式 :DORP INDEX IndexName ON tab_name;

2、使用索引的优缺点

创建索引可以大大提高系统的性能 可以大大加快数据的检索速度


索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。

第一,   创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二,   索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
第三,   当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。



一般来说,应该在这些列上创建索引。
第一,   在经常需要搜索的列上,可以加快搜索的速度;
第二,   在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
第三,   在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
第四,   在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
第五,   在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
第六,   在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。


一般来说,不应该创建索引的的这些列具有下列特点:
第一,在查询中很少使用列不应该创建索引。
第二,对于只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。


3、组合索引

    组合索引的生效原则是  从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用;

造成断点的原因:

    前边的任意一个索引没有参与查询,后边的全部不生效。

    前边的任意一个索引字段参与的是范围查询,后面的不会生效。

    断点跟索引字字段在SQL语句中的位置前后无关,只与是否存在有关。

where a=3 and b=45 and c=5 .... #这种三个索引顺序使用中间没有断点,全部发挥作用;where a=3 and c=5... #这种情况下b就是断点,a发挥了效果,c没有效果where b=3 and c=4... #这种情况下a就是断点,在a后面的索引都没有发挥作用,这种写法联合索引没有发挥任何效果;where b=45 and a=3 and c=5 .... #这个跟第一个一样,全部发挥作用,abc只要用上了就行,跟写的顺序无关

(a,b,c) 三个列上加了联合索引(是联合索引 不是在每个列上单独加索引)而是建立了a,(a,b),(a,b,c)三个索引,另外(a,b,c)多列索引和 (a,c,b)是不一样的。

(0) select * from mytable where a=3 and b=5 and c=4;#abc三个索引都在where条件里面用到了,而且都发挥了作用(1) select * from mytable where c=4 and b=6 and a=3;#这条语句为了说明 组合索引与在SQL中的位置先后无关,where里面的条件顺序在查询之前会被mysql自动优化,效果跟上一句一样(2) select * from mytable where a=3 and c=7;#a用到索引,b没有用,所以c是没有用到索引效果的(3) select * from mytable where a=3 and b>7 and c=3;#a用到了,b也用到了,c没有用到,这个地方b是范围值,也算断点,只不过自身用到了索引(4) select * from mytable where b=3 and c=4;#因为a索引没有使用,所以这里 bc都没有用上索引效果(5) select * from mytable where a>4 and b=7 and c=9;#a用到了  b没有使用,c没有使用(a使用的是范围查询)(6) select * from mytable where a=3 order by b;#a用到了索引,b在结果排序中也用到了索引的效果,前面说了,a下面任意一段的b是排好序的(7) select * from mytable where a=3 order by c;#a用到了索引,但是这个地方c没有发挥排序效果,因为中间断点了,使用 explain 可以看到 filesort(8) select * from mytable where b=3 order by a;#b没有用到索引,排序中a也没有发挥索引效果

在查询时,MYSQL只能使用一个索引,如果建立的是多个单列的普通索引,在查询时会根据查询的索引字段,从中选择一个限制最严格的单例索引进行查询。别的索引都不会生效。


第三部分:MySQL优化:explain分析


Explain是Mysql的自带查询优化器,负责select语句的优化器模块,可以模拟优化器执行SQL查询语句,从而知道Mysql是如何处理SQL的,语法也很简单:Explain + SQL



1、id:反映的是表的读取的顺序,或查询中执行select子句的顺序。

小表永远驱动大表,三种情况:

(1)id相同,执行顺序是由上至下的

(2)id不同,如果是子查询,id序号会递增,id值越大优先级越高,越先被执行

(3)id存在相同的,也存在不同的,所有组中,id越大越先执行,如果id相同的,从上往下顺序执行

  数据库优化总结

  derived是衍生虚表的意思,derived2中的2对应id2

2、select_type:反映的是Mysql理解的查询类型

(1)simple:简单的select查询,查询中不包含子查询或union。

(2)primary:查询中若包含任何复杂的字部分,最外层查询标记为primary。

(3)subquery:select或where列表中的子查询。

(4)derived(衍生):在from列表中包含的子查询,Mysql会递归执行这些子查询,把结果放在临时表里。

(5)union:若第二个select出现在union后,则被标记为union,若union包含在from字句的子查询中,外层select将被标记为derived

(6)union result:union后的结果集

3、table:反映这一行数据是关于哪张表的

4、type:访问类型排序

反映sql优化的状态,至少达到range级别,最好能达到ref

查询效率:system > const > eq_ref > ref > range > index > all

  (完整的排序:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index >all)  

(1)system:从单表只查出一行记录(等于系统表),这是const类型的特例,一般不会出现

(2)const:查询条件用到了常量,通过索引一次就找到,常在使用primary key或unique索引中出现。

   数据库优化总结

  where id=1写死,所以类型是const

(3)eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一索引扫描。

(4)ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它可能会找到多个符合条件的行,与eq_ref的差别是eq_ref只匹配了一条记录。

(5)range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般是在where语句中出现了between、<、>、in等的查询。

   这种范围扫描索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。与eq_ref和ref的区别在于筛选条件不是固定值,是范围。

  数据库优化总结

(6)index:full Index scan,index和all的区别为index类型只遍历索引树。这通常比all快,因为索引文件通常比数据文件小。

  数据库优化总结

  要获得的id信息,刚好id在索引上,从索引中读取

   (all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)

(7)all:全表扫描,如果查询数据量很大时,全表扫描效率是很低的。

5、possible_keys、key、key_len:反映实际用到了哪个索引,索引是否失效

(1)possible_keys:Mysql推测可能用到的索引有哪些,但不一定被查询实际使用

(2)key:实际使用的索引,若为null,则可能没建索引或索引失效。

     数据库优化总结

  (查询中若使用了覆盖索引,则该索引仅出现在key列表中。

  覆盖索引:select后面的字段和所建索引的个数、顺序一致)

(3)key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。同样的查询结果下,长度越短越好。

    key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。

6、ref:反映哪些列或常量被用于查找索引列上的值

   数据库优化总结

7、rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

  数据库优化总结

  仅通过主键索引查找是641行

   数据库优化总结

  建完相关的复合索引再查,需要查询的行数就变少了

8、Extra

(1)using filesort:mysql中无法利用索引完成的排序,这时会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。

    数据库优化总结

  创建索引时就会对数据先进行排序,出现using filesort一般是因为order by后的条件导致索引失效,最好进行优化。

   数据库优化总结

  order by的排序最好和所建索引的顺序和个数一致

(2)using temporary:使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。

   数据库优化总结

  影响更大,所以要么不建索引,要么group by的顺序要和索引一致

   数据库优化总结

(3)using index:表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,效率好

  覆盖索引:select后的数据列只从索引就能取得,不必读取数据行,且与所建索引的个数(查询列小于等于索引个数)、顺序一致。

  所以如果要用覆盖索引,就要注意select的列只取需要用到的列,不用select *,同时如果将所有字段一起做索引会导致索引文件过大,性能会下降。

  

  出现using where,表明索引被用来执行索引键值的查找

   

  如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。

(4)using where:表明使用了where过滤

(5)using join buffer:使用了连接缓存

(6)impossible where:where子句的值是false

(7)select tables optimized away

(8)distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作


















以上是关于数据库优化总结的主要内容,如果未能解决你的问题,请参考以下文章

使用 C++ 反转句子中的每个单词需要对我的代码片段进行代码优化

如何优化C ++代码的以下片段 - 卷中的零交叉

从JVM的角度看JAVA代码--代码优化

python常用代码片段总结

BootStrap有用代码片段(持续总结)

js数组遍历方法总结