【发布时间】:2020-10-30 05:25:35
【问题描述】:
我正在调整一个查询,该查询在数百万条记录上运行 select distinct。我对执行计划有点缺乏经验,但我对 distinct 的理解是,我们希望避免使用它,因为清除重复记录需要额外的开销。
有没有办法在不使用 distinct 的情况下重写下面的示例?
IF OBJECT_ID('TEMPDB..#ORDERS', 'U') IS NOT NULL
DROP TABLE #ORDERS
IF OBJECT_ID('TEMPDB..#CUSTOMERS', 'U') IS NOT NULL
DROP TABLE #CUSTOMERS
CREATE TABLE #ORDERS (OrderLineItemID INT IDENTITY(1, 1), OrderID INT, PRIMARY KEY (OrderLineItemID));
CREATE TABLE #CUSTOMERS (CustomerID INT, OrderLineItemID INT, PRIMARY KEY (OrderLineItemID));
INSERT INTO #ORDERS (OrderID)
VALUES (1), (1), (1), (2), (2), (2), (2), (3), (3), (3), (3), (3), (3), (3), (5), (5), (5), (5), (5), (5);
INSERT INTO #CUSTOMERS (OrderLineItemID, CustomerID)
SELECT OrderLineItemID, CASE
WHEN OrderLineItemID <= 3
THEN 15
ELSE 20
END
FROM #ORDERS
查询结果需要拉取CustomerID和OrderID,但是每个订单里面都有一个单独的line item。下面拉出所有结果。
SELECT C.CustomerID, O.OrderID
FROM #CUSTOMERS C
JOIN #ORDERS O ON C.OrderLineItemID = O.OrderLineItemID
非明显结果:
CustomerID OrderID
15 1
15 1
15 1
20 2
20 2
20 2
20 2
20 3
20 3
20 3
20 3
20 3
20 3
20 3
20 5
20 5
20 5
20 5
20 5
20 5
但如果我们在选择中添加 distinct,我们会得到想要的结果。
SELECT DISTINCT C.CustomerID, O.OrderID
FROM #CUSTOMERS C
JOIN #ORDERS O ON C.OrderLineItemID = O.OrderLineItemID
不同的结果:
CustomerID OrderID
15 1
20 2
20 3
20 5
有没有更好的写法来提高效率?
【问题讨论】:
-
一般来说,如果一个成熟的系统提供了一个内置的方法来做某事,你可能不会写一个更有效的解决方法。
-
您的架构似乎是主要问题。一般来说,schema问题会导致tsql繁琐且效率低下。为什么我说“问题”?我不知道订单与不同客户相关联的现实情况 - 在您的情况下,订单中的每个项目都与客户相关。解决架构问题可能会解决许多问题。
-
这只是一个例子。真实数据其实与订单无关。我把它放在一起来演示非不同连接查询将如何返回重复与不同。
-
因此,如上所述,您的情况具有误导性,使 cmets 和建议的用处降低。但是一般的含义是 - 使用 DISTINCT 的需要通常是由模式问题或逻辑上有缺陷的查询引起的。 Oso 是正确的——你可能无法胜过内置函数。我还要指出,您的结果集没有排序,并且行顺序通常很重要。由于运行时因素,DISTINCT 通常会导致行显示为有序 - 但不能保证。
-
cmets 仍然适用,因为该示例的设置方式与我查询的源完全相同。我本可以让列标题更加模棱两可,如果这引起了混乱,我很抱歉。无论如何,在这种情况下,如果不对架构进行大修,就没有解决方法。将这些放在一起的开发人员无意进行增强。感谢您的建议。
标签: sql-server tsql duplicates distinct