首页 > 解决方案 > 在这种情况下,如何避免使用不同的 TSQL 选择?

问题描述

我正在调整一个在数百万条记录上运行 select 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

有没有更好的方法来编写它以更有效地执行?

标签: sql-servertsqlduplicatesdistinct

解决方案


您可以使用窗口函数ROW_NUMBER()来实现相同的结果。不确定,它是否会提供更好的性能。如有疑问,最好测试一下。

SELECT CustomerID, OrderID
FROM
(
SELECT C.CustomerID, O.OrderID, ROW_NUMBER() OVER(PARTITION BY C.CustomerID, O.OrderID ORDER BY (SELECT 1)) AS RNK
FROM #CUSTOMERS C
JOIN #ORDERS O ON C.OrderLineItemID = O.OrderLineItemID) as t
WHERE rnk = 1

推荐阅读