У меня есть представление 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
Теперь предположим, что общее количество строк в этом представлении составляет ~ 1 миллион, а выполнение select * из productView занимает 10 секунд. Выполнение запроса, такого как select * from productView, где 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
Я думаю, что это заставляет внутренний подзапрос каждый раз оцениваться полностью. В идеале я хотел бы использовать что-то вроде следующего
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
Но это, похоже, недопустимо. Есть ли способ сделать что-то подобное?
РЕДАКТИРОВАТЬ -
После долгих экспериментов реальная проблема, которая, как мне кажется, у меня возникла, заключается в том, как заставить объединение вернуть ровно 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)
При указанном выше примере выборки запрос «получить все» ниже
select * from Products
outer apply (select top 1 *
from Customers
where Products.id = Customers.productID) Customers
требуется ~ 1000 мс для запуска. Добавление явного условия:
select * from Products
outer apply (select top 1 *
from Customers
where Products.id = Customers.productID) Customers
where Customers.value = 'Value 45872'
Занимает одинаковое количество времени. Эти 1000 мс для довольно простого запроса уже слишком велики и неправильно масштабируются (вверх) при добавлении дополнительных похожих объединений.