SQL优化:优化select语句

优化select语句

  • 为了使慢速SELECT ... WHERE查询更快,首先要检查的是是否可以添加索引。为避免浪费磁盘空间,请构造组合索引
  • 调整函数调用,使函数调用从一多次减少为一次,从而极大地提高了效率。
  • 定期使用ANALYZE TABLE使表统计信息保持最新 ,为优化器提供构造有效执行计划所需的信息。
  • 阅读EXPLAIN计划并调整索引。
  • 调整MySQL用于缓存的内存区域的大小和属性。
  • 避免锁导致的查询性能问题。

1. WHERE子句优化

  • 删除不必要的括号。

       ((a AND b) AND c OR (((a AND b) AND (c AND d))))
    -> (a AND b AND c) OR (a AND b AND c AND d)
    
  • 常量折叠。

     (a<b AND b=c) AND a=5
    -> b>5 AND b=c AND a=5
    
  • 常量条件消除。

       (b>=5 AND b=5) OR (b=6 AND 5=5) OR (b=7 AND 5=6)
    -> b=5 OR b=6
    
  • 使用索引的常量表达式仅计算一次。

  • 直接从MyISAMMEMORY表中检索没有WHERE的单个表上的COUNT(*)。

  • 无效的常量表达式。

    SELECT * FROM t WHERE a<0 AND a>1;								︶︵︶				
    
  • 如果没有使用GROUP BY或者聚合函数(如COUNT(), MIN())等)就将HAVING字句合并到WHERE字句。

       SELECT * FROM t WHERE a=1 HAVING b>1;
    -> SELECT * FROM t WHERE a=1 AND b>1;
    
  • 对于联接中的每个表,构造一个更简单的WHERE以获得表的快速WHERE评估,并尽快跳过行。(复杂的WHERE会延迟每一行数据的过滤时间)

  • 在查询的所有表中,优先读取常量表。常量表可以是以下任意一个

    • 空表或者只有一行数据的表;

    • 与PRIMARY KEY或UNIQUE索引上的WHERE子句一起使用的表,其中所有索引部分都与常量表达式进行比较,并定义为NOT NULL;

      以下所有表均用作常量表:

      SELECT * FROM t WHERE primary_key=1;
      SELECT * FROM t1,t2 WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
      
  • 如果ORDER BYGROUP BY子句中的所有列都来自同一表,则在连接时优先使用该表。

  • ORDER BYGROUP BY 包含连接队列中第一个表以外的表中的列,则会创建一个临时表(用于连接后数据集的排序,排序后自动删除)。

  • 在索引中的所有列都是数字列的情况下,MySQL甚至可以在不查询数据文件的情况下从索引读取行。

  • 在输出每一行之前,HAVING将跳过不匹配该子句的那些行 。(HAVING时对结果集做裁剪,并不能减少扫描行数)

快速查询示例:

SELECT COUNT(*) FROM tbl_name;

SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;

SELECT MAX(key_part2) FROM tbl_name WHERE key_part1=constant;

SELECT ... FROM tbl_name ORDER BY key_part1,key_part2,... LIMIT 10;

SELECT ... FROM tbl_name ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;

假设索引列是数字,MySQL仅使用索引树来解析以下查询:

SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;

SELECT COUNT(*) FROM tbl_name
  WHERE key_part1=val1 AND key_part2=val2;

SELECT key_part2 FROM tbl_name GROUP BY key_part1;

以下查询使用索引来按排序顺序检索行,而无需单独的排序遍历:

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... ;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... ;

2. 范围优化

对于 BTREE 和 HASH 索引,当使用=、<=>、IN、IS NULL 或者 IS NOT NULL 操作符时 ,

关键元素与常量值的比较关系对应一个范围条件。

  • HASH索引使用 =, <=>, IN(),IS NULL,或IS NOT NULL操作符的等式比较会很快。
  • BTREE索引使用 >, <, >=, <=, BETWEEN, !=,或 <> ,LIKE ‘pattern’(其中 'pattern’不以通配符开始)操作符,关键元素与常量值的比较关系对应一个范围条件

范围优化器尝试从WHERE子句中为每个可能的索引提取范围条件 。在提取过程中,删除了不能用于构建范围条件的条件,合并了产生重叠范围的条件,并删除了产生空范围的条件。优化过程请参考单部分索引的范围访问方法

2.1 多值比较的等距范围优化
CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2));
INSERT INTO t1 VALUES
  (1,1), (1,2), (1,3), (1,4), (1,5),
  (2,1), (2,2), (2,3), (2,4), (2,5);
INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
ANALYZE TABLE t1;
EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40;

MySQL可以选择索引扫描以获取所有行,然后根据子句中的f2 > 40 条件WHERE以产生最终结果集。范围扫描比全索引扫描更有效,但是在这种情况下不能使用,因为没有条件在第一个索引列f1上 。但是,从MySQL 8.0.13开始,优化器可以使用一种称为“skip scan”的方法,将一次范围扫描分为多次范围扫描,再将多次扫描的结果合并返回。

算法的运行方式如下:

  1. 获取第一个索引的第一个不同值(f1 = 1)。
  2. 根据第一和第二索引构造范围(f1 = 1 AND f2 > 40)。
  3. 执行范围扫描。
  4. 获取第一个索引的下一个不同值(f1 = 2)。
  5. 根据第一和第二索引构造范围(f1 = 2 AND f2 > 40)。
  6. 执行范围扫描。

使用此策略可减少访问的行数,因为MySQL会跳过不符合每个构造范围的行。此“skip scan”访问方法适用于以下情况:

  • 表T具有至少一个复合索引,其索引的形式为([A_1,…,A_ k,] B_1,…,B_ m,C [,D_1,…,D_ n])。关键部分A和D可能为空,但B和C必须为非空。。
  • 该查询仅使用一个表。
  • 查询不使用GROUP BYDISTINCT
  • 该查询仅引用索引中的列。
  • 前缀A_1,…,A_ *k*必须是相等谓词,并且它们必须是常量。这包括 IN()
  • 该查询必须是一个联合查询。即, ANDOR 条件。
  • C上必须有范围条件
  • 允许在D字段上有过滤条件,但是必须和C上的范围条件一起使用。

对于使用了跳跃范围扫描特性的SQL,使用EXPLAIN查看其执行计划,可以看到:

  • 在执行计划输出的Extra一栏中有: Using index for skip scan
  • 在执行计划输出的possible_keys一栏中会显示可以使用到的索引
2.2 行构造函数表达式的范围优化

优化程序可以将范围扫描访问方法应用于以下形式的查询:

SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ));

为了使优化器使用范围扫描,查询必须满足以下条件:

  • 仅使用IN()谓词,不使用NOT IN()。

  • 在IN()谓词的左侧 ,行构造器仅包含列引用。

  • 在IN()谓词的右侧 ,行构造器仅包含运行时常量。

  • 在IN()谓词的右侧 ,有多个行构造器。

参考:Optimizing SELECT Statements

发布了8 篇原创文章 · 获赞 32 · 访问量 8348

猜你喜欢

转载自blog.csdn.net/qq_36011946/article/details/104777428