zoukankan      html  css  js  c++  java
  • SQL优化汇总

    今天面某家公司,然后问我SQL优化,感觉有点忘了,今天特此总结一下:

     总结得是分两方面:索引优化和查询优化;

    一. 索引优化:

    1. 独立的列

    在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引。

    例如下面的查询不能使用 actor_id 列的索引:

    #这是错误的
    SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;

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

    SELECT actor_id FROM sakila.actor WHERE actor_id  = 5 - 1;

    2. 多列索引

    在需要使用多个列作为条件进行查询时,使用多列索引比使用多个单列索引性能更好。

    例如下面的语句中,最好把actor_id 和 film_id 设置为多列索引。猿辅导有道题,详见链接,可以让理解更深刻。

    SELECT film_id, actor_ id FROM sakila.film_actor
    WHERE actor_id = 1 AND film_id = 1;

    3. 索引列的顺序

    让选择性最强的索引列放在前面。MySql最左前缀原则

    索引的选择性是指:不重复的索引值和记录总数的比值。最大值为 1,此时每个记录都有唯一的索引与其对应。选择性越高,每个记录的区分度越高,查询效率也越高。

    例如下面显示的结果中 customer_id 的选择性比 staff_id 更高,因此最好把 customer_id 列放在多列索引的前面。

    SELECT COUNT(DISTINCT staff_id)/COUNT(*) AS staff_id_selectivity,
    COUNT(DISTINCT customer_id)/COUNT(*) AS customer_id_selectivity,
    COUNT(*)
    FROM payment;
    
    #结果如下
    staff_id_selectivity: 0.0001
    customer_id_selectivity: 0.0373
    COUNT(*): 16049

    4. 前缀索引

    对于 BLOB、TEXT 和 VARCHAR 类型的列,必须使用前缀索引,只索引开始的部分字符。

    前缀长度的选取需要根据索引选择性来确定。

    5. 覆盖索引

    索引包含所有需要查询的字段的值。具有以下优点:

    • 索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。

    • 一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以不使用系统调用(通常比较费时)。

    • 对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。

    以下为优先使用索引,避免全表扫描:

    6. mysql在使用like进行模糊查询的时候把%放后面,避免开头模糊查询

    因为mysql在使用like查询的时候只有使用后面的%时,才会使用到索引。

    如:'%ptd_' 和 '%ptd_%' 都没有用到索引;而 'ptd_%' 使用了索引。

    #进行全表查询,没有用到索引
    EXPLAIN SELECT * FROM `user` WHERE username LIKE '%ptd_%';
    EXPLAIN SELECT * FROM `user` WHERE username LIKE '%ptd_';
    
    #有用到索引
    EXPLAIN SELECT * FROM `user` WHERE username LIKE 'ptd_%';

     再比如:经常用到的查询数据库中姓张的所有人:

    SELECT * FROM `user` WHERE username LIKE '张%';

    7. 在表中建立索引,优先考虑where、group by使用到的字段

    8. 尽量避免使用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)

    9. 尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描

    如:

    SELECT * FROM t WHERE id = 1 OR id = 3

    优化方式:可以用union代替or。如下:

    SELECT * FROM t WHERE id = 1
    UNION
    SELECT * FROM t WHERE id = 3

    10. 尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描

    SELECT * FROM t WHERE score IS NULL

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

    SELECT * FROM t WHERE score = 0

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

    同第1个,单独的列;

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

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

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

    12. 当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描

    SELECT * FROM t WHERE 1=1

    优化方式:用代码拼装sql时进行判断,没where加where,有where加and。

    索引的好处:建立索引后,查询时不会扫描全表,而会查询索引表锁定结果。

    索引的缺点:在数据库进行DML操作的时候,除了维护数据表之外,还需要维护索引表,运维成本增加。

    应用场景:数据量比较大,查询字段较多的情况。

    索引规则:

    1.选用选择性高的字段作为索引,一般unique的选择性最高;

    2.复合索引:选择性越高的排在越前面。(左前缀原则);

    3.如果查询条件中两个条件都是选择性高的,最好都建索引;

    参考:

    1. 索引的特点和应用场景

     2. SQL优化面试

    二、查询优化

    1. 使用Explain进行分析

    Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain 结果来优化查询语句。

    比较重要的字段有:

    • select_type : 查询类型,有简单查询、联合查询、子查询等;

    • key : 使用的索引;

    • rows : 扫描的行数;

     

    2. 优化数据访问

    1. 减少请求的数据量

    • 只返回必要的列:最好不要使用 SELECT * 语句。

    • 只返回必要的行:使用 LIMIT 语句来限制返回的数据。

    • 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的。

    1. 减少服务器端扫描的行数

    • 最有效的方式是使用索引来覆盖查询。

    3. 重构查询方式

           1. 切分大查询

    一个大查询如果一次性执行的话,可能一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。

    1. 分解大连接查询

    将一个大连接查询分解成对每一个表进行一次单表查询,然后在应用程序中进行关联,这样做的好处有:

    • 让缓存更高效:对于连接查询,如果其中一个表发生变化,那么整个查询缓存就无法使用。而分解后的多个查询,即使其中一个表发生变化,对其它表的查询缓存依然可以使用。

    • 分解成多个单表查询,这些单表查询的缓存结果更可能被其它查询使用到,从而减少冗余记录的查询。

    • 减少锁竞争

    • 应用层进行连接,可以更容易对数据库进行拆分,从而更容易做到高性能和可伸缩。

    • 查询本身效率也可能会有所提升。例如下面的例子中,使用 IN() 代替连接查询,可以让 MySQL 按照 ID 顺序进行查询,这可能比随机的连接要更高效。

    SELECT * FROM tab
    JOIN tag_post ON tag_post.tag_id=tag.id
    JOIN post ON tag_post.post_id=post.id
    WHERE tag.tag='mysql';
    
    SELECT * FROM tag WHERE tag='mysql';
    SELECT * FROM tag_post WHERE tag_id=1234;
    SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);
  • 相关阅读:
    golang删除数组某个元素
    golang用通道实现信号量,控制并发个数
    什么是ScaleIO中的forwards rebuild和backwards rebuild?
    SQL Server中的database checkpoint
    如何将thick provision lazy zeroed的VMDK文件转换为thick provision eager zeroed?
    LoadTestAgentResultsLateException in VS2010
    SQL Server Instance无法启动了, 因为TempDB所在的分区没有了, 怎么办?
    VMware vCenter中, 如何辩认虚机上Raw Device Mapping过了的一块物理磁盘?
    SQL Server AlwaysOn Setup Step-By-Step Guide
    TPC-E在populate测试Database时需要注意的一些事项
  • 原文地址:https://www.cnblogs.com/gjmhome/p/11438652.html
Copyright © 2011-2022 走看看