语句实例(行为表 t1 与业绩表 t2 关联):
with t as (
select 行为id ,
t1.行为时间 ,
t2.用户id ,
t2.业绩时间 ,
row_number () over (partition by t1.用户id order by t1.行为时间 desc ) as rnk
from 行为表 t1
join 业绩表 t2 on t1.用户id = t2.用户id and t1.行为时间 < t2.业绩时间
)
select t.行为id , t.行为时间 ,t.用户id, t.业绩时间 from t where t.rnk = 1
1、索引的优化
创建合适的索引
1 -1 、对 行为表 和 业绩表 中的 用户id 列创建索引,以提高 JOIN 操作的效率。
1 -2 、对 行为时间 和 业绩时间 列创建索引,以优化条件过滤和排序
1 -3 、如果查询中经常包含其他筛选条件(如 t1.行为时间 < t2.业绩时间),可以考虑使用复合索引,如 (用户id, 行为时间) 和 (用户id, 业绩时间)。
2、减少数据量
限制扫描范围
在 行为时间 和 业绩时间 之前进行过滤时,如果可以在 JOIN 前减少数据量,将大大提高性能。
SELECT t1.行为id, t1.行为时间, t2.用户id, t2.业绩时间
FROM 行为表 t1
JOIN 业绩表 t2
ON t1.用户id = t2.用户id
AND t1.行为时间 < t2.业绩时间
WHERE t2.业绩时间 > '2024-01-01' ;
3、减少冗余计算
3-1、避免不必要的列
在查询中只选择必要的列,避免返回不需要的列,尤其是在使用 SELECT * 时,会增加不必要的开销。
3-2、减少子查询
减少不必要的嵌套子查询或重复计算,可以通过 WITH 子句(CTE)或者窗口函数来减少计算量。
4、使用窗口函数
利用 ROW_NUMBER ()、RANK () 等窗口函数可以高效地为每个用户排序并筛选出所需的数据。特别是结合 PARTITION BY 和 ORDER BY ,可以减少复杂的聚合操作。
5、分区表
如果数据量非常大,可以考虑对表进行 分区(如按日期或用户 ID 分区),这样在执行查询时只需要扫描相关的分区,减少了全表扫描的开销。
6、批量操作
减少单次操作的数据量
如果你处理的数据量非常大,建议分批处理数据。通过将查询分成多个小批次执行,减少单次查询的负载,避免内存压力过大。
7、避免使用过多的 DISTINCT
如果查询结果不要求绝对去重,尽量避免使用 DISTINCT 。DISTINCT 需要额外的排序步骤,会增加计算开销。
8、使用合适的 JOIN 类型
根据业务逻辑,选择合适的 JOIN 类型。避免使用不必要的 LEFT JOIN 或者 FULL JOIN
9、分析 SQL 执行计划
使用 EXPLAIN 分析 SQL 执行计划:
通过 EXPLAIN 查看数据库如何执行查询。你可以看到是否有全表扫描、是否使用了索引、关联操作的顺序等。根据这些信息,进一步调整查询。
EXPLAIN
SELECT t1.行为id, t1.行为时间,t2.用户id, t2.业绩时间
FROM 行为表 t1
JOIN 业绩表 t2
ON t1.用户id = t2.用户id
AND t1.行为时间 < t2.业绩时间;
10、并行查询
如果数据库支持并行查询(如 PostgreSQL 或 Oracle 等),可以利用多核处理器加快大数据量查询的执行时间
总结:
1 、创建合适的索引,尤其是对于 用户id、行为时间 和 业绩时间 列进行单列或复合索引优化。
2 、在 JOIN 之前减少数据量,通过过滤条件限制行为表中的数据行。
3 、使用窗口函数优化排序和分组,避免过多的嵌套查询。
4 、分析执行计划,调整索引、过滤条件及 JOIN 顺序,减少全表扫描。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
2022-09-22 Maven-基础