sql >> Database >  >> RDS >> Sqlserver

Een weergave maken met de ORDER BY-component

Ik weet niet zeker wat je hiervan vindt ORDER BY presteert? Zelfs als je doe zet ORDER BY in de weergave op een legale manier (bijvoorbeeld door een TOP . toe te voegen clausule), als u gewoon uit de weergave selecteert, b.v. SELECT * FROM dbo.TopUsersTest; zonder een ORDER BY clausule staat het SQL Server vrij om de rijen op de meest efficiënte manier te retourneren, wat niet noodzakelijkerwijs overeenkomt met de volgorde die u verwacht. Dit komt omdat ORDER BY is overbelast, in die zin dat het twee doelen probeert te dienen:om de resultaten te sorteren en om te dicteren welke rijen moeten worden opgenomen in TOP . In dit geval TOP wint altijd (hoewel je, afhankelijk van de index die is gekozen om de gegevens te scannen, kunt opmerken dat je bestelling werkt zoals verwacht - maar dit is gewoon toeval).

Om te bereiken wat je wilt, moet je je ORDER BY . toevoegen clausule toe aan de query's die gegevens uit de weergave halen, niet aan de code van de weergave zelf.

Dus je weergavecode zou gewoon moeten zijn:

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];

De ORDER BY is zinloos en zou dus niet eens moeten worden opgenomen.

Ter illustratie, met AdventureWorks2012, hier is een voorbeeld:

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;

Resultaten:

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

En u kunt aan het uitvoeringsplan zien dat de TOP en ORDER BY zijn absoluut genegeerd en weggeoptimaliseerd door SQL Server:

Er is geen TOP operator helemaal niet, en geen soort. SQL Server heeft ze volledig geoptimaliseerd.

Als u nu de weergave wijzigt in ORDER BY SalesID , krijg je dan toevallig de volgorde die de weergave aangeeft, maar alleen - zoals eerder vermeld - bij toeval.

Maar als u uw buitenste zoekopdracht wijzigt om de ORDER BY . uit te voeren je wilde:

SELECT SalesOrderID, OrderDate, CustomerID, AccountNumber, TotalDue
FROM dbo.SillyView
ORDER BY CustomerID;

U krijgt de resultaten geordend zoals u dat wilt:

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

En het plan is nog steeds geoptimaliseerd weg de TOP /ORDER BY in de weergave, maar er is een sortering toegevoegd (zonder kleine kosten, let wel) om de resultaten te presenteren, gesorteerd op CustomerID :

Dus, moraal van het verhaal, zet geen ORDER BY in views. Zet ORDER BY in de zoekopdrachten die ernaar verwijzen. En als het sorteren duur is, kunt u overwegen een index toe te voegen/aan te passen om dit te ondersteunen.



  1. MySQL JOIN met LIMIT 1 op samengevoegde tafel

  2. CHECK-beperking in MySQL werkt niet

  3. Heeft Mysql een equivalent van @@ROWCOUNT zoals in mssql?

  4. Hoe de SPACE()-functie werkt in SQL Server (T-SQL)