调优百万级数据SQL查询:如何避免使用SELECT DISTINCT并提升性能?
嘿,针对百万级数据的去重查询,确实有比DISTINCT更高效的替代方案,而且逻辑上也更清晰。咱们先拆解问题本质:之所以关联后会出现重复,是因为一个OrderID对应多条OrderLineItemID,而这些LineItem又关联同一个CustomerID,最终产生了重复的组合。下面给你几个实用的优化写法:
方案1:用GROUP BY替代DISTINCT
这是最直接的替代方式,逻辑和DISTINCT完全一致,但在很多场景下,数据库优化器对GROUP BY的处理会更灵活(比如后续要加聚合逻辑时扩展性更强):
SELECT C.CustomerID, O.OrderID FROM #CUSTOMERS C JOIN #ORDERS O ON C.OrderLineItemID = O.OrderLineItemID GROUP BY C.CustomerID, O.OrderID
效果和你原有的DISTINCT查询完全一样,但写法更符合“分组取唯一”的语义。对于你的测试数据,执行计划可能和DISTINCT类似,但在大数据量下,部分数据库会选择更优的分组策略。
方案2:提前过滤重复关联项(大数据量推荐)
核心思路是先减少关联的数据量,再进行关联,避免后续的全量去重操作。因为每个OrderID对应的CustomerID是唯一的(从你的示例数据看是这样),我们可以先给每个OrderID只保留一条对应的OrderLineItemID,再关联到#CUSTOMERS:
SELECT C.CustomerID, O.OrderID FROM ( -- 给每个OrderID只取第一条LineItem SELECT OrderID, OrderLineItemID, ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY OrderLineItemID) AS rn FROM #ORDERS ) O JOIN #CUSTOMERS C ON O.OrderLineItemID = C.OrderLineItemID WHERE O.rn = 1
这种方法的优势在于:关联前就把#ORDERS的数据量压缩到唯一OrderID的数量(比如你的示例里从20条降到4条),大大减少了后续关联和去重的开销,对于百万级数据来说,性能提升会很明显。
如果你的数据库支持TOP 1 WITH TIES或者类似语法,也可以写成更简洁的版本:
SELECT C.CustomerID, O.OrderID FROM ( SELECT TOP 1 WITH TIES OrderID, OrderLineItemID FROM #ORDERS ORDER BY ROW_NUMBER() OVER (PARTITION BY OrderID ORDER BY OrderLineItemID) ) O JOIN #CUSTOMERS C ON O.OrderLineItemID = C.OrderLineItemID
方案3:用CROSS APPLY获取唯一映射
如果数据模型中OrderID和CustomerID是一一对应的,还可以用CROSS APPLY直接获取每个OrderID对应的CustomerID:
SELECT O.OrderID, C.CustomerID FROM #ORDERS O CROSS APPLY ( SELECT TOP 1 CustomerID FROM #CUSTOMERS C WHERE C.OrderLineItemID = O.OrderLineItemID ) C GROUP BY O.OrderID, C.CustomerID
额外优化建议
- 索引优化:确保
#ORDERS上有OrderID的非聚集索引(方便快速分组取唯一值),#CUSTOMERS的OrderLineItemID已经是主键,所以主键索引会自动生效。 - 数据模型验证:如果业务上
OrderID和CustomerID确实是一一对应的,建议在#ORDERS表直接添加CustomerID字段,这样就不需要关联查询,直接取DISTINCT CustomerID, OrderID即可,性能会提升一个量级。
内容的提问来源于stack exchange,提问作者Lozik

