SELECT name FROM employees WHERE department_id = 10;department_id创建索引:CREATE INDEX idx_department_id ON employees(department_id);SELECT * FROM employees WHERE department_id = 10;SELECT name FROM employees WHERE department_id = 10;技巧: 子查询通常效率低,JOIN性能更好。
案例:
问题SQL:
SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location = 'New York');优化:使用JOIN代替子查询:
SELECT e.name FROM employees e JOIN departments d ON e.department_id = d.id WHERE d.location = 'New York';EXPLAIN或EXPLAIN ANALYZE来查看SQL查询的执行计划,找到性能瓶颈。EXPLAIN SELECT name FROM employees WHERE department_id = 10;ORDER BY 会消耗大量资源,尤其是大数据量时,只有在需要排序时才使用。SELECT name FROM employees WHERE department_id = 10 ORDER BY hire_date;ORDER BY。LIMIT,对于大偏移量的查询,可以通过索引或缓存减少开销。SELECT name FROM employees ORDER BY hire_date LIMIT 100000, 10;SELECT name FROM employees WHERE id > 100000 ORDER BY hire_date LIMIT 10;SELECT name FROM employees WHERE YEAR(hire_date) = 2023;SELECT name FROM employees WHERE hire_date BETWEEN '2023-01-01' AND '2023-12-31';SELECT * FROM employees WHERE department_id = 10 AND status = 'active';status放在索引前面:CREATE INDEX idx_status_department ON employees(status, department_id);技巧: 批量插入可以显著减少IO和锁的开销。
案例:
问题SQL: 每次插入一条记录:
INSERT INTO employees (name, department_id) VALUES ('John', 10);优化: 使用批量插入:
INSERT INTO employees (name, department_id) VALUES ('John', 10), ('Alice', 20), ('Bob', 30);技巧: NOT IN性能较差,改用NOT EXISTS或LEFT JOIN。
案例:
问题SQL:
SELECT name FROM employees WHERE department_id NOT IN (SELECT id FROM departments);优化: 使用LEFT JOIN:
SELECT e.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id WHERE d.id IS NULL;技巧: 只有在真正有重复数据时才使用DISTINCT。
案例:
问题SQL:
SELECT DISTINCT name FROM employees WHERE department_id = 10;优化: 如果不需要去重,移除DISTINCT。
技巧: 尽量使用INNER JOIN,除非明确需要所有数据,避免使用LEFT JOIN或RIGHT JOIN。
案例:
问题SQL:
SELECT e.name, d.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id;优化: 改为INNER JOIN:
SELECT e.name, d.name FROM employees e INNER JOIN departments d ON e.department_id = d.id;CREATE TABLE employees (
id INT,
name VARCHAR(50),
hire_date DATE
)
PARTITION BY RANGE (YEAR(hire_date)) (
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022)
);GROUP BY查询。SELECT department_id, COUNT(*) FROM employees GROUP BY department_id;技巧: 对大量IN操作,可以将数据放到临时表中,使用JOIN代替。
案例:
问题SQL:
SELECT name FROM employees WHERE department_id IN (1, 2, 3, 4, 5);优化: 将ID放入临时表:
CREATE TEMPORARY TABLE temp_ids (id INT);
INSERT INTO temp_ids (id) VALUES (1), (2), (3), (4), (5);
SELECT e.name FROM employees e JOIN temp_ids t ON e.department_id = t.id;LOCK IN SHARE MODE)。SELECT * FROM employees WHERE id = 10 FOR UPDATE;INSERT INTO SELECT语句中使用索引,提高性能。INSERT INTO employees_backup (id, name) SELECT id, name FROM employees WHERE hire_date < '2020-01-01';innodb_buffer_pool_size)来匹配查询需求。这些技巧可以帮助大多数SQL查询在不同场景下提高性能,但每种数据库和业务场景都有其特定的优化需求,因此调优时应根据实际情况灵活应用。
技巧: 在分布式数据库环境中,尽量减少跨节点的数据传输,优化查询计划以提高查询效率。
案例:
问题SQL: 查询在多个分区节点上操作
SELECT e.name, d.name
FROM employees e JOIN departments d
ON e.department_id = d.id
WHERE e.location = 'New York';优化: 将与location相关的数据先在本地节点处理,再进行全局数据汇总,避免跨节点传输。
技巧: 在多列上进行查询时,如果无法为每个查询场景创建组合索引,数据库会尝试通过索引合并来提高性能。
案例:
问题SQL: 使用多个单列索引
SELECT * FROM orders WHERE customer_id = 10 AND product_id = 5;优化: 数据库可以将customer_id和product_id的单列索引合并执行。结合EXPLAIN分析,数据库是否使用了索引合并功能。
技巧: 使用CUBE和ROLLUP进行多维聚合分析,减少多次单独的GROUP BY操作。
案例:
GROUP BY分析SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id;
SELECT region, SUM(sales) FROM sales_data GROUP BY region;ROLLUP进行多层次的聚合分析,减少多次查询SELECT department_id, region, SUM(sales) FROM sales_data
GROUP BY department_id, region WITH ROLLUP;技巧: 使用窗口函数(如ROW_NUMBER()、RANK()、LAG()、LEAD())进行复杂分析,避免自连接或嵌套查询。
案例:
SELECT a.*, (SELECT sales FROM sales_data b WHERE b.id = a.id - 1) AS previous_sales
FROM sales_data a;SELECT id, sales, LAG(sales, 1) OVER (ORDER BY id) AS previous_sales
FROM sales_data;技巧: 对非常大的表使用分区裁剪技术,减少数据扫描范围。
案例:
SELECT * FROM transactions WHERE transaction_date BETWEEN '2023-01-01' AND '2023-01-31';CREATE TABLE transactions (
id INT,
amount DECIMAL(10, 2),
transaction_date DATE
)
PARTITION BY RANGE (YEAR(transaction_date)) (
PARTITION p2023 VALUES LESS THAN (2024)
);技巧: 尽量减少复杂查询中的临时表使用,因为它们会导致磁盘I/O,影响性能。
案例:
CREATE TEMPORARY TABLE temp_sales AS
SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id;WITH temp_sales AS (
SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id
)
SELECT * FROM temp_sales;技巧: 充分利用数据库的并行查询能力,尤其在数据量巨大的查询时,开启并行执行计划提高效率。
案例:
SELECT SUM(sales) FROM sales_data;ALTER SESSION ENABLE PARALLEL QUERY;
SELECT /*+ PARALLEL(sales_data, 4) */ SUM(sales) FROM sales_data;技巧: 对复杂的聚合查询,可以使用物化视图(Materialized View)将计算结果存储起来,避免每次查询重新计算。
案例:
SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id;CREATE MATERIALIZED VIEW mv_sales_data AS
SELECT department_id, SUM(sales) AS total_sales FROM sales_data GROUP BY department_id;技巧: 在高并发环境下,避免使用全表锁或行锁,可以通过索引锁和锁定必要行的方式减少锁争用。
案例:
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;SELECT * FROM orders WHERE order_id = 123 FOR UPDATE;技巧: 对于长时间运行的事务,应尽量减少锁定时间,避免不必要的锁持有,减少表锁定范围。
案例:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT;BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;
BEGIN;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT;