Tôi không chắc bạn nghĩ gì về điều này ORDER BY
đang hoàn thành? Ngay cả khi bạn làm đặt ORDER BY
trong chế độ xem theo cách hợp pháp (ví dụ:bằng cách thêm TOP
mệnh đề), nếu bạn chỉ chọn từ chế độ xem, ví dụ:SELECT * FROM dbo.TopUsersTest;
không có ORDER BY
, SQL Server miễn phí trả về các hàng theo cách hiệu quả nhất, không nhất thiết phải khớp với thứ tự bạn mong đợi. Điều này là do ORDER BY
bị quá tải, trong đó nó cố gắng phục vụ hai mục đích:sắp xếp kết quả và chỉ định những hàng nào cần đưa vào TOP
. Trong trường hợp này, TOP
luôn thắng (mặc dù tùy thuộc vào chỉ mục được chọn để quét dữ liệu, bạn có thể thấy rằng đơn đặt hàng của mình đang hoạt động như mong đợi - nhưng đây chỉ là sự trùng hợp ngẫu nhiên).
Để đạt được những gì bạn muốn, bạn cần thêm ORDER BY
của mình mệnh đề cho các truy vấn lấy dữ liệu từ chế độ xem, không phải mã của chính chế độ xem.
Vì vậy, mã chế độ xem của bạn chỉ nên là:
CREATE VIEW [dbo].[TopUsersTest]
AS
SELECT
u.[DisplayName], SUM(a.AnswerMark) AS Marks
FROM
dbo.Users_Questions AS uq
INNER JOIN [dbo].[Users] AS u
ON u.[UserID] = us.[UserID]
INNER JOIN [dbo].[Answers] AS a
ON a.[AnswerID] = uq.[AnswerID]
GROUP BY u.[DisplayName];
ORDER BY
là vô nghĩa vì vậy thậm chí không nên đưa vào.
Để minh họa bằng cách sử dụng AdventureWorks2012, đây là một ví dụ:
CREATE VIEW dbo.SillyView
AS
SELECT TOP 100 PERCENT
SalesOrderID, OrderDate, CustomerID , AccountNumber, TotalDue
FROM Sales.SalesOrderHeader
ORDER BY CustomerID;
GO
SELECT SalesOrderID, OrderDate, CustomerID, AccountNumber, TotalDue
FROM dbo.SillyView;
Kết quả:
SalesOrderID OrderDate CustomerID AccountNumber TotalDue
------------ ---------- ---------- -------------- ----------
43659 2005-07-01 29825 10-4020-000676 23153.2339
43660 2005-07-01 29672 10-4020-000117 1457.3288
43661 2005-07-01 29734 10-4020-000442 36865.8012
43662 2005-07-01 29994 10-4020-000227 32474.9324
43663 2005-07-01 29565 10-4020-000510 472.3108
Và bạn có thể thấy từ kế hoạch thực thi rằng TOP
và ORDER BY
đã hoàn toàn bị SQL Server bỏ qua và tối ưu hóa:
Không có TOP
toán tử ở tất cả, và không có phân loại. SQL Server đã tối ưu hóa chúng hoàn toàn.
Bây giờ, nếu bạn thay đổi chế độ xem để nói ORDER BY SalesID
, sau đó bạn sẽ chỉ tình cờ nhận được thứ tự mà chế độ xem nêu ra, nhưng chỉ - như đã đề cập trước đây - một cách trùng hợp.
Nhưng nếu bạn thay đổi truy vấn bên ngoài của mình để thực hiện ORDER BY
bạn muốn:
SELECT SalesOrderID, OrderDate, CustomerID, AccountNumber, TotalDue
FROM dbo.SillyView
ORDER BY CustomerID;
Bạn nhận được kết quả được sắp xếp theo cách bạn muốn:
SalesOrderID OrderDate CustomerID AccountNumber TotalDue
------------ ---------- ---------- -------------- ----------
43793 2005-07-22 11000 10-4030-011000 3756.989
51522 2007-07-22 11000 10-4030-011000 2587.8769
57418 2007-11-04 11000 10-4030-011000 2770.2682
51493 2007-07-20 11001 10-4030-011001 2674.0227
43767 2005-07-18 11001 10-4030-011001 3729.364
Và kế hoạch vẫn tối ưu hóa TOP
/ ORDER BY
trong chế độ xem, nhưng một sắp xếp được thêm vào (với chi phí không nhỏ, bạn nhớ nhé) để trình bày kết quả được sắp xếp theo CustomerID
:
Vì vậy, đạo lý của câu chuyện, không đặt ORDER BY trong các lượt xem. Đặt ORDER BY trong các truy vấn tham chiếu đến chúng. Và nếu việc phân loại là tốn kém, bạn có thể xem xét thêm / thay đổi một chỉ mục để hỗ trợ nó.