- 使用 WHERE 子句等过滤条件,减少返回结果集的数据量。
- 尽可能在关联前进行数据过滤,减少关联操作。
- 避免使用 SELECT *,只选择你需要的字段,减少数据传输量
eg 假设有一个订单管理系统,需要优化以下 SQL 查询:
SELECT * FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE orders.order_date > '2022-01-01'
加入订单表 orders 和客户表 customers 很可能都包含大量数据,我们可以首先尝试在WHERE 子句中加入更多的过滤条件
,例如根据地区、订单状态等,以减少返回结果集的数据量。
eg 假设有两张表,一张是用户表(User),另一张是订单表(Order)。用户表中存储了用户的基本信息,订单表中存储了用户的订单信息,两张表通过用户ID进行关联。
当需要查询所有在过去一周内下过订单的活跃用户信息时,为了减少关联操作
并提高性能,可以先从订单表中筛选出在过去一周内下过订单的用户ID,然后再根据这些用户ID去查询用户表中的用户信息
SELECT u.*
FROM User u
WHERE u.user_id IN (
SELECT DISTINCT o.user_id
FROM `Order` o
WHERE o.order_date >= DATE_SUB(NOW(), INTERVAL 1 WEEK)
);
比对操作:避免了直接对两张表中的数据进行比对操作,因为通过子查询方式,我们可以先筛选出满足条件的数据再进行查询,避免了在关联阶段进行大量的比对操作。
- 确保查询的字段上建立了索引,并保证索引的有效性。
- 优化 SQL 查询语句中的关联条件,确保索引被充分利用。
SELECT * FROM orders
JOIN customers ON orders.customer_id = customers.id
WHERE orders.order_date > '2022-01-01'
确保 orders 表中的 order_date 字段和 customers 表中的 id 字段上都建立了索引,提高查询效率
- 避免在
关联
条件中对字段进行函数处理
原因:索引失效: 当在关联条件中对字段进行函数处理时,数据库引擎通常无法有效使用索引。因为对字段进行函数处理后,原本的字段值发生了改变,使得无法直接匹配索引中的值,从而导致索引失效,数据库引擎可能无法有效地利用索引进行高效的数据查找。
假设我们有两个表 orders 和 customers,orders 表存储订单信息,customers 表存储客户信息,我们需要根据订单金额和客户等级进行关联查询。
首先,让我们看一下 orders 表的数据示例:
| order_id | amount |
|----------|--------|
| 1 | 100.5 |
| 2 | 200.8 |
| 3 | 300.3 |
customers 表的数据示例:
| customer_id | level |
|-------------|-------|
| 1 | 101 |
| 2 | 200 |
| 3 | 300 |
原始的 SQL 查询可能如下,其中对订单金额字段进行了舍入处理:
SELECT *
FROM orders o
JOIN customers c ON ROUND(o.amount) = c.level;
为了避免在 JOIN 条件中进行函数处理,我们可以将数据处理提前到查询前。首先创建带有舍入后金额的临时表 tmp_orders:
CREATE TEMPORARY TABLE tmp_orders AS
SELECT order_id, ROUND(amount) AS rounded_amount
FROM orders;
然后基于处理后的数据进行关联查询:
SELECT *
FROM tmp_orders t
JOIN customers c ON t.rounded_amount = c.level;
通过这样的处理,我们在查询前即对订单金额进行了舍入处理并存储在临时表中,避免在关联条件中对字段进行函数处理,使得查询更加简洁和高效。
- 将复杂计算的结果存储在临时表中:
原因:1、简化复杂逻辑: 复杂计算的结果存储在临时表中可以将复杂的逻辑简化为一个简单的数据访问操作,使得查询语句更加清晰和易于维护。
2、减少重复计算: 复杂计算通常会消耗较多的计算资源,将计算结果存储在临时表中可以避免重复进行这些复杂计算。在后续的查询中,直接访问临时表中的结果,无需重复进行耗时的计算,从而提高了查询的效率
假设我们有一个订单表 orders,需要从中筛选出订单金额大于一定阈值的订单,并计算订单金额超出阈值部分的差值。
首先,让我们看一下 orders 表的数据示例:
| order_id | amount |
|----------|--------|
| 1 | 900 |
| 2 | 1100 |
| 3 | 1200 |
原始的 SQL 查询可能如下,计算订单金额超出阈值部分的差值:
SELECT order_id, amount,
CASE
WHEN amount > 1000 THEN amount - 1000
ELSE 0
END AS excess_amount
FROM orders
WHERE amount > 1000;
为了提高查询效率,我们可以将计算结果存储在临时表中,并后续查询该临时表。首先创建包含计算结果的临时表 tmp_excess_orders:
CREATE TEMPORARY TABLE tmp_excess_orders AS
SELECT order_id, amount,
CASE
WHEN amount > 1000 THEN amount - 1000
ELSE 0
END AS excess_amount
FROM orders
WHERE amount > 1000;
然后可以直接查询这个临时表来获取结果:
SELECT *
FROM tmp_excess_orders;
- 索引并不是越多越好,索引固然可以提高相应的select的效率,但同时也降低了insert 及 update 的效率
原因:索引建立越多,底层B树结构每个节点存储信息就越多,插入新数据可能需要重新平衡树结构,这可能涉及移动和重新排序节点,从而增加了操作的开销
- 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
原因:
1、查询性能提升:数字型字段比字符型字段在查询时通常具有更好的性能。数据库引擎可以更快地处理数字型数据的比较、排序和计算操作,相比之下,字符型数据需要更多的资源和时间来进行相同的操作。
2、提高连接性能:在数据库连接操作中,如果连接字段是数字型而不是字符型,连接操作的效率通常会更高。连接操作需要比较两个字段的值,并且通过索引来加速连接操作;对于数字型字段,比较和索引查找的效率通常比字符型字段更高。
可能导致全表扫描的几种情况:
- 尽量避免使用in和not in,在where子句中使用in和not in,引擎将放弃使用索引而进行全表扫描。
- 尽量避免使用!=或<>操作符,在 where语句中使用!=或<>,引擎将放弃使用索引而进行全表扫描。
- 使用like的时候要注意是否会导致全表扫
慢sql查询怎么查
- 开启慢查询日志:
在 MySQL 数据库中,您可以通过编辑 MySQL 配置文件 my.cnf
,找到并修改以下选项:
slow_query_log = 1
long_query_time = 1
将 slow_query_log
设为 1
以开启慢查询日志记录,long_query_time
指定慢查询的时间阈值,单位为秒。这里设置为 1
表示超过 1 秒的查询会被记录在慢查询日志中。
- 分析慢查询日志
定期检查慢查询日志文件,您可以使用以下命令找到慢查询日志文件路径:
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'slow_query_log_file';
通过查看慢查询日志,您可以找到执行时间较长的 SQL 查询语句。
- 使用数据库性能分析工具
针对慢查询的 SQL 语句,您可以使用 MySQL 的 EXPLAIN
命令来查看查询执行计划,例如:
EXPLAIN SELECT * FROM your_table WHERE condition;
这将会显示查询执行计划以及可能的性能瓶颈,帮助您理解查询的执行方式和可能的优化路径。
- 优化 SQL 查询
根据分析结果,您可以针对性地对慢查询的 SQL 语句进行优化,例如添加索引、重构查询语句、优化数据库配置等。
面试题:
统计年龄在 19 到 24 岁之间年龄最大的人数
SELECT COUNT(*) AS max_age_count
FROM table_name
WHERE age >= 19 AND age <= 24
ORDER BY age DESC
LIMIT 1;
COUNT(*) ?
COUNT(*) 是 SQL 中用于统计符合特定条件的行数的聚合函数。它可以用来统计表中满足条件的记录的数量。
例如,如果您有一个名为 "students" 的表,其中包含了学生的信息,您可以使用 COUNT(*) 来统计表中的记录数量,如下所示:
SELECT COUNT(*) AS total_students
FROM students;
这将返回一个名为 "total_students" 的结果集,其中包含了表中记录的总数。
您也可以使用 COUNT(*) 结合 WHERE 子句来统计满足特定条件的记录数量,例如:
SELECT COUNT(*) AS passed_students
FROM students
WHERE score >= 60;
这将返回一个名为 "passed_students" 的结果集,其中包含了分数大于等于 60 分的学生的记录数量。
总之,COUNT(*) 是 SQL 中非常常用的聚合函数,用于统计行数,可以帮助您快速获取所需信息的数量统计。