Mam widok sql, którego używam do pobierania danych. Powiedzmy, że jest to duża lista produktów, które są powiązane z klientami, którzy je kupili. Widok powinien zwracać tylko jeden wiersz na produkt, niezależnie od liczby klientów, z którymi jest połączony. Używam funkcji row_number, aby to osiągnąć. (Ten przykład jest uproszczony, rodzajowy sytuacja byłaby zapytanie tam gdzie powinien być tylko jeden rząd powrócił do każdej unikatowej wartości jakiejś kolumny X. który jest zwracany wiersz nie jest ważna)Refaktoryzacja widoku tsql, który używa row_number() do zwracania wierszy z unikalną wartością kolumny
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
Teraz powiedzmy, że całkowita liczba wierszy w tym widoku wynosi ~ 1 milion, a wybór opcji * z productView zajmuje 10 sekund. Wykonywanie kwerendy, takie jak wybierz * z productView gdzie productID = 10 trwa tyle samo czasu. Wierzę, że to dlatego, że zapytanie zostanie oceniona na tym
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
myślę, że to jest przyczyną wewnętrzną podkwerenda być oceniane w pełni każdej chwili. Idealnie chciałbym użyć czegoś wzdłuż następujących linii:
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
Ale wydaje się, że to nie jest dozwolone. Czy istnieje sposób na zrobienie czegoś podobnego?
EDIT -
Po wielu eksperymentach, rzeczywisty problem wierzę, mam to w jaki sposób wymusić dołączyć do powrotu dokładnie 1 wiersz. Próbowałem użyć zewnętrznego zastosowania, jak sugerowano poniżej. Jakiś przykładowy kod.
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)
Z powyższego zestawu próbek, 'dostać wszystko' query poniżej
select * from Products
outer apply (select top 1 *
from Customers
where Products.id = Customers.productID) Customers
trwa ~ 1000ms uruchomić. Dodanie wyraźnego warunku:
select * from Products
outer apply (select top 1 *
from Customers
where Products.id = Customers.productID) Customers
where Customers.value = 'Value 45872'
Trwa to samo identycznie. To 1000ms dla dość prostej kwerendy jest już za dużo i skaluje się w niewłaściwy sposób (w górę) przy dodawaniu dodatkowych podobnych sprzężeń.
Czy potrzebujesz rzeczywistych danych klienta lub po prostu istnienia lub po prostu IDklienta? Podzapyt jest oceniany, ponieważ "10" nie jest znane z góry. I pytasz dokładnie o 10. wiersz. Stąd moje pierwsze pytanie o pożądaną wydajność – gbn
Naprawdę dobra obserwacja - SQL nie jest w stanie zastosować filtra widoku do podzapytania. Czy naprawdę potrzebujesz elastyczności widoku? Jeśli użyłeś funkcji SPROC lub funkcji wycenionej w tabeli z "zdefiniowanymi" filtrami (ProductID w twoim przykładzie), możesz wbudować filtr w podzapytanie. A w przypadku, gdy twoja PARTYCJA PRZEZ i FILTR są takie same (ProductId), nie potrzebujesz wcale PARTYCJI - więc SELECT TOP 1 powinien wystarczyć. – StuartLC
Potrzebuję rzeczywistych informacji o kliencie (lub wartości zerowych, jeśli nie istnieją), a nie tylko o istnieniu jednego. Muszę też użyć widoku, refaktoryzując aplikację, która pobiera dane nie jest możliwa. – John