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已经太多了,并且在添加其他类似连接时缩放错误的方式(向上).
如果你做了类似的事情怎么办:
SELECT ...
FROM products
OUTER APPLY (SELECT TOP 1 * from customer where customerid = products.buyerid) as customer
...
Run Code Online (Sandbox Code Playgroud)
那么 ProductId 上的过滤器应该会有所帮助。不过,如果不进行过滤,情况可能会更糟。