重构tsql视图,该视图使用row_number()返回具有唯一列值的行

Joh*_*ohn 5 sql t-sql sql-server sql-view

我有一个sql视图,我用它来检索数据.让我们说一大堆产品,这些产品与购买它们的顾客有关.无论链接到多少客户,每个产品的视图应仅返回一行.我正在使用row_number函数来实现这一点.(此示例已简化,通用情况将是一个查询,其中应该只为某列X的每个唯一值返回一行.返回哪一行并不重要)

CREATE VIEW productView AS
SELECT * FROM 
    (SELECT 
        Row_number() OVER(PARTITION BY products.Id ORDER BY products.Id) AS product_numbering,
        customer.Id
        //various other columns
    FROM products
    LEFT OUTER JOIN customer ON customer.productId = prodcut.Id
    //various other joins
    ) as temp
WHERE temp.prodcut_numbering = 1
Run Code Online (Sandbox Code Playgroud)

现在假设此视图中的总行数约为100万,而从productView运行select*需要10秒.从productView执行查询,例如select*,其中productID = 10需要相同的时间.我相信这是因为查询得到了评估

SELECT * FROM 
    (SELECT 
        Row_number() OVER(PARTITION BY products.Id ORDER BY products.Id) AS product_numbering,
        customer.Id
        //various other columns
    FROM products
    LEFT OUTER JOIN customer ON customer.productId = prodcut.Id
    //various other joins
    ) as temp
WHERE prodcut_numbering = 1 and prodcut.Id = 10
Run Code Online (Sandbox Code Playgroud)

我认为这会导致内部子查询每次都被完整评估.理想情况下,我想使用以下几行

SELECT 
    Row_number() OVER(PARTITION BY products.productID ORDER BY products.productID) AS product_numbering,
    customer.id
    //various other columns
FROM products
    LEFT OUTER JOIN customer ON customer.productId = prodcut.Id
    //various other joins
WHERE prodcut_numbering = 1
Run Code Online (Sandbox Code Playgroud)

但似乎不允许这样做.有没有办法做类似的事情?

编辑 -

经过多次实验,我相信我遇到的实际问题是如何强制连接返回正好1行.我尝试使用外部应用,如下所示.一些示例代码.

CREATE TABLE Products (id int not null PRIMARY KEY)
CREATE TABLE Customers (
        id int not null PRIMARY KEY,
        productId int not null,
        value varchar(20) NOT NULL)

declare @count int = 1
while @count <= 150000
begin
        insert into Customers (id, productID, value)
        values (@count,@count/2, 'Value ' + cast(@count/2 as varchar))      
        insert into Products (id) 
        values (@count)
        SET @count = @count + 1
end

CREATE NONCLUSTERED INDEX productId ON Customers (productID ASC)
Run Code Online (Sandbox Code Playgroud)

使用上面的示例集,下面是"获取所有内容"查询

select * from Products
outer apply (select top 1 * 
            from Customers
            where Products.id = Customers.productID) Customers
Run Code Online (Sandbox Code Playgroud)

需要大约1000毫秒才能运行.添加显式条件:

select * from Products
outer apply (select top 1 * 
            from Customers
            where Products.id = Customers.productID) Customers
where Customers.value = 'Value 45872'
Run Code Online (Sandbox Code Playgroud)

花费相同的时间.对于一个相当简单的查询,这1000ms已经太多了,并且在添加其他类似连接时缩放错误的方式(向上).

Gil*_*ilM 2

如果你做了类似的事情怎么办:

SELECT ...
FROM products
OUTER APPLY (SELECT TOP 1 * from customer where customerid = products.buyerid) as customer
...
Run Code Online (Sandbox Code Playgroud)

那么 ProductId 上的过滤器应该会有所帮助。不过,如果不进行过滤,情况可能会更糟。