Tôi có chế độ xem sql mà tôi đang sử dụng để truy xuất dữ liệu. Cho phép nói một danh sách lớn các sản phẩm, được liên kết với khách hàng đã mua chúng. Chế độ xem sẽ chỉ trả lại một hàng cho mỗi sản phẩm, bất kể số lượng khách hàng được liên kết đến. Tôi đang sử dụng hàm row_number để đạt được điều này. (Ví dụ này được đơn giản hóa, tình huống chung sẽ là một truy vấn mà chỉ nên có một hàng được trả lại cho mỗi giá trị duy nhất của một số cột X. Hàng nào được trả về không quan trọng)Tái cấu trúc chế độ xem tsql sử dụng row_number() để trả về các hàng có giá trị cột duy nhất
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
Bây giờ cho phép nói rằng tổng số hàng trong chế độ xem này là ~ 1 triệu và chạy * từ productView mất 10 giây. Thực hiện truy vấn như chọn * từ productView trong đó productID = 10 mất cùng một lượng thời gian. Tôi tin rằng điều này là do truy vấn được đánh giá cho điều này
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
Tôi nghĩ điều này khiến cho truy vấn con bên trong được đánh giá đầy đủ mỗi lần. Lý tưởng nhất là tôi muốn sử dụng thứ gì đó dọc theo các dòng sau
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
Nhưng điều này dường như không được phép. Có cách nào để làm một cái gì đó tương tự?
EDIT -
Sau nhiều thử nghiệm, vấn đề thực tế Tôi tin rằng tôi đang gặp là làm thế nào để buộc một tham gia trở lại chính xác 1 hàng. Tôi đã cố gắng sử dụng bên ngoài áp dụng, như đề nghị dưới đây. Một số mã mẫu.
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)
Với các thiết lập ví dụ trên, các truy vấn 'có được mọi thứ' bên dưới
select * from Products
outer apply (select top 1 *
from Customers
where Products.id = Customers.productID) Customers
mất ~ 1000ms để chạy. Thêm điều kiện rõ ràng:
select * from Products
outer apply (select top 1 *
from Customers
where Products.id = Customers.productID) Customers
where Customers.value = 'Value 45872'
Mất một khoảng thời gian giống nhau. 1000ms này cho một truy vấn khá đơn giản đã quá nhiều, và quy mô sai cách (trở lên) khi thêm các phép nối tương tự bổ sung.
Bạn có cần chi tiết khách hàng thực tế hay chỉ là sự tồn tại của hay chỉ là một customerid? Truy vấn phụ là evaluatde vì "10" không được biết trước. Và bạn đang yêu cầu hàng thứ 10 chính xác. Do đó câu hỏi đầu tiên của tôi về đầu ra mong muốn – gbn
Quan sát thực sự tốt - SQL không thể áp dụng bộ lọc chế độ xem vào truy vấn phụ. Bạn có thực sự cần sự linh hoạt của chế độ xem không? Nếu bạn đã sử dụng hàm SPROC hoặc bảng có giá trị với bộ lọc 'đã xác định' (ProductID trong ví dụ của bạn), bạn có thể xây dựng trong bộ lọc vào truy vấn phụ. Và trong trường hợp PARTITION BY của bạn và FILTER là giống nhau (ProductId), bạn sẽ không cần PARTITION chút nào - vì vậy SELECT TOP 1 phải là đủ. – StuartLC
Tôi cần chi tiết thực tế của khách hàng (hoặc giá trị null nếu không tồn tại), không chỉ sự tồn tại của một. Tôi cũng phải sử dụng chế độ xem, việc tái cấu trúc ứng dụng để truy xuất dữ liệu là không thể. – John