Home
img of docs

探索如何使用 SQL 执行计划分析查询逻辑,找出性能瓶颈并通过索引优化和重构查询语句来提升查询效率。

chou403

/ Database

/ c:

/ u:

/ 5 min read


SQL执行计划,怎么看,如何优化

SQL 执行计划是数据库查询优化的关键工具,它描述了 SQL 查询的执行步骤和策略。通过阅读执行计划,您可以了解查询的效率,找出潜在的性能瓶颈,并进行优化。以下是如何查看和优化 SQL 执行计划的指南:

查看执行计划

MySQL

使用 EXPLAIN 语句可以查看查询的执行计划:

   EXPLAIN SELECT * FROM employees WHERE age > 30;
PostgreSQL

使用 EXPLAIN 语句:

   EXPLAIN SELECT * FROM employees WHERE age > 30;

要查看更详细的执行计划,可以使用 EXPLAIN ANALYZE:

   EXPLAIN ANALYZE SELECT * FROM employees WHERE age > 30;
SQL Server

使用 SET SHOWPLAN_ALL 或图形化工具(SQL Server Management Studio):

   SET SHOWPLAN_ALL ON;
GO
SELECT * FROM employees WHERE age > 30;
GO
SET SHOWPLAN_ALL OFF;
GO

解释执行计划

执行计划通常包括以下几个部分:

  • id: 查询执行的顺序。
  • select_type: 查询的类型(SIMPLE, PRIMARY, UNION, SUBQUERY)。
  • table: 正在访问的表。
  • type: 访问类型(ALL, INDEX, RANGE, REF, EQ_REF, CONST)。
  • possible_keys: 可以使用的索引。
  • key: 实际使用的索引。
  • key_len: 索引的长度。
  • ref: 使用的列或常量。
  • rows: 预估的扫描行数。
  • extra: 其他信息(Using where, Using index, Using filesort)。

优化技巧

  1. 使用合适的索引:

    • 确保在查询条件中使用的列上创建了索引,尤其是 WHERE 子句,JOIN 子句,ORDER BY 和 GROUP BY 子句中使用的列。
    • 使用复合索引来覆盖多个列。
       CREATE INDEX idx_age ON employees(age);
  2. 避免全表扫描:

    • 尽量避免使用 SELECT *,只选择需要的列。
    • 使用 WHERE 子句来减少扫描的行数。
  3. 优化 JOIN:

    • 确保连接列上有索引。
    • 优化 JOIN 顺序,使用小表驱动大表。
       EXPLAIN SELECT e.name, d.department
    FROM employees e
    JOIN departments d ON e.department_id = d.id
    WHERE e.age > 30;
  4. 使用覆盖索引:

    • 覆盖索引可以让查询只从索引中获取数据,而不必访问表。
       CREATE INDEX idx_name_age ON employees(name, age);
  5. 优化子查询:

    • 尽量避免使用相关子查询,使用 JOIN 或 EXISTS 替代。
       -- 子查询
    SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location = 'NY');
    
    -- 优化为 JOIN
    SELECT e.name
    FROM employees e
    JOIN departments d ON e.department_id = d.id
    WHERE d.location = 'NY';
  6. 避免使用函数操作列:

    • 避免在 WHERE 子句中对列使用函数,这会阻止索引的使用。
       -- 不推荐
    SELECT * FROM employees WHERE YEAR(hire_date) = 2020;
    
    -- 推荐
    SELECT * FROM employees WHERE hire_date BETWEEN '2020-01-01' AND '2020-12-31';
  7. 分区表:

    • 对于大表,可以使用分区表来提高查询效率。
       CREATE TABLE employees (
        id INT,
        name VARCHAR(50),
        age INT,
        hire_date DATE
    )
    PARTITION BY RANGE (age) (
        PARTITION p0 VALUES LESS THAN (20),
        PARTITION p1 VALUES LESS THAN (30),
        PARTITION p2 VALUES LESS THAN (40),
        PARTITION p3 VALUES LESS THAN MAXVALUE
    );
  8. 使用缓存:

    • 利用数据库的查询缓存或应用层缓存,减少重复查询的开销。

示例优化

假设有一个查询:

   SELECT * FROM employees WHERE age > 30;

使用 EXPLAIN 查看执行计划:

   EXPLAIN SELECT * FROM employees WHERE age > 30;

输出可能是:

   +----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 1000000 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+---------+-------------+

这里的 typeALL,表示全表扫描,可以通过创建索引来优化:

   CREATE INDEX idx_age ON employees(age);

再次查看执行计划:

   EXPLAIN SELECT * FROM employees WHERE age > 30;

输出可能是:

   +----+-------------+-----------+-------+---------------+--------+---------+------+-------+-----------------------+
| id | select_type | table     | type  | possible_keys | key    | key_len | ref  | rows  | Extra                 |
+----+-------------+-----------+-------+---------------+--------+---------+------+-------+-----------------------+
|  1 | SIMPLE      | employees | range | idx_age       | idx_age| 4       | NULL | 50000 | Using where; Using index |
+----+-------------+-----------+-------+---------------+--------+---------+------+-------+-----------------------+

这里的 typerange,表示使用了索引,查询性能显著提高。

总结

通过查看 SQL 执行计划,您可以识别查询的性能瓶颈并采取适当的优化措施。关键在于理解执行计划中的每个部分以及如何通过索引优化,避免全表扫描,优化 JOIN,使用覆盖索引等方法来提高查询性能。