sql >> Database >  >> RDS >> Database

Top 3 tips die u moet weten om snellere SQL-weergaven te schrijven

Vriend of vijand? De weergaven van SQL Server waren een onderwerp van verhitte discussies toen ik in mijn eerste jaar SQL Server gebruikte. Ze zeiden dat het slecht was omdat het traag was. Maar hoe zit het met vandaag?

Zit je in hetzelfde schuitje als ik vele jaren geleden? Ga dan met me mee op deze reis om de echte deal over SQL-weergaven te ontrafelen, zodat je ze zo snel mogelijk kunt schrijven.

SQL-views zijn virtuele tabellen. De records in een weergave zijn het resultaat van een query erin. Telkens wanneer de basistabellen die in de weergave worden gebruikt, worden bijgewerkt, wordt de weergave ook bijgewerkt. U kunt in sommige gevallen ook records INSERT, UPDATE en DELETE in een weergave als een tabel. Hoewel ik dit zelf niet heb geprobeerd.

Net als bij een tabel kunt u een weergave MAKEN, WIJZIGEN of DROPPEN. Je kunt zelfs een index maken, met enkele beperkingen.

Merk op dat ik SQL Server 2019 heb gebruikt in de voorbeeldcodes.

1. Ken het juiste en onjuiste gebruik van SQL-weergaven

Eerst de basis.

Waar zijn SQL-weergaven voor?

Het is cruciaal. Als je het als een hamer voor een schroevendraaier gebruikt, vergeet dan de snellere SQL-weergaven. Laten we eerst eens kijken naar het juiste gebruik:

  • Om de perceptie van elke gebruiker van de database te focussen, vereenvoudigen en aanpassen.
  • Om de gebruikers toegang te geven tot de enige informatie die ze om veiligheidsredenen nodig hebben.
  • Om achterwaartse compatibiliteit te bieden aan een oude tabel of een oud schema om afhankelijke apps niet te breken. Het is tijdelijk totdat alle benodigde wijzigingen zijn voltooid.
  • Om gegevens van verschillende servers te partitioneren. Daarom zien ze eruit alsof ze één tabel zijn van één server of instantie.

Hoe GEEN SQL Server-weergaven gebruiken?

  • Hergebruik de weergave in een andere weergave die in weer een andere weergave zal worden hergebruikt. Kortom, diep genestelde opvattingen. Het hergebruik van de code heeft in dit geval enkele nadelen.
  • Bespaar op toetsaanslagen. Het heeft betrekking op de eerste, die de vingerdruk vermindert en het coderen lijkt te versnellen.

Onjuist gebruik van weergaven, indien toegestaan, verdoezelt de echte reden waarom u weergaven maakt. Zoals u later zult zien, wegen de echte voordelen op tegen de waargenomen voordelen van oneigenlijk gebruik.

Voorbeeld

Laten we een voorbeeld van Microsoft bekijken. De vEmployee uitzicht vanaf AdventureWorks . Hier is de code:

-- Employee names and basic contact information
CREATE VIEW [HumanResources].[vEmployee] 
AS 
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
 ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID];
GO

Het doel van deze weergave is gericht op de basisinformatie van werknemers. Indien nodig door een personeelsfunctionaris, kan het op een webpagina worden weergegeven. Werd het hergebruikt in andere weergaven?

Probeer dit:

  1. In SQL Server Management Studio , zoek naar de AdventureWorks database.
  2. Breid de map Views uit uit en zoek naar [HumanResources].[vEmployee].
  3. Klik er met de rechtermuisknop op en selecteer Afhankelijkheden bekijken .

Als je een andere weergave ziet, afhankelijk van deze weergave, die vervolgens weer afhankelijk is van een andere weergave, heeft Microsoft ons een slecht voorbeeld gegeven. Maar dan zijn er geen andere weergave-afhankelijkheden.

Laten we naar de volgende gaan.

2. Ontkracht de mythe over SQL-weergaven

Wanneer SQL Server een SELECT uit een weergave verwerkt , het evalueert de code in de view VOORDAT het de WHERE-component of een join in de outer query behandelt. Als er meer tabellen zijn toegevoegd, zal het traag zijn in vergelijking met een SELECTEER uit basistabellen met dezelfde resultaten.

Tenminste, dat is wat mij werd verteld toen ik SQL begon te gebruiken. Of het nu een mythe is of niet, er is maar één manier om erachter te komen. Laten we een praktisch voorbeeld nemen.

Hoe SQL-weergaven werken

Microsoft liet ons niet in het ongewisse om eindeloos te debatteren. We hebben de tools om te zien hoe zoekopdrachten werken, zoals STATISTICS IO en het Daadwerkelijke uitvoeringsplan . We zullen deze in al onze voorbeelden gebruiken. Laten we de eerste nemen.

USE AdventureWorks
GO

SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

Om te zien wat er gebeurt wanneer SQL Server de weergave verwerkt, bekijken we het Actual Execution Plan in Figuur 1. We vergelijken het met de CREATE VIEW code voor vEmployee in het vorige gedeelte.

Zoals u kunt zien, zijn de eerste knooppunten die door SQL Server worden verwerkt, degene die INNER JOIN gebruiken. Vervolgens gaat het verder met het verwerken van de LEFT OUTER JOINs.

Aangezien we nergens een filterknooppunt kunnen zien voor de WHERE-component, moet het zich in een van die knooppunten bevinden. Als u de eigenschappen van alle knooppunten inspecteert, ziet u de WHERE-clausule verwerkt in de tabel Werknemer. Ik heb het ingesloten in een kader in figuur 1. Om te bewijzen dat het er is, zie figuur 2 voor de eigenschappen van dat knooppunt:

Analyse

Dus, had de SELECT-instructie in de vEmployee view geëvalueerd of verwerkt VOORDAT de WHERE-clausule werd toegepast? Uit het Uitvoeringsplan blijkt van niet. Als dat zo was, zou het het dichtst bij het SELECT-knooppunt moeten verschijnen.

Wat mij werd verteld was een mythe. Ik vermeed iets goeds vanwege een misverstand over het juiste gebruik van SQL-views.

Nu we weten hoe SQL Server een SELECT uit een view verwerkt , blijft de vraag:is het langzamer dan het niet gebruiken van een weergave?

SELECT FROM View vs. SELECT FROM Base Tables – welke zal sneller werken?

Eerst moeten we de SELECT-instructie extraheren in de vEmployee bekijken en hetzelfde resultaat opleveren als bij het gebruik van de weergave. De onderstaande code toont dezelfde WHERE-clausule:

USE AdventureWorks
GO

-- SELECT FROM a view
SELECT * FROM HumanResources.vEmployee e
WHERE e.BusinessEntityID = 105

-- SELECT FROM Base Tables
SELECT 
    e.[BusinessEntityID]
    ,p.[Title]
    ,p.[FirstName]
    ,p.[MiddleName]
    ,p.[LastName]
    ,p.[Suffix]
    ,e.[JobTitle]  
    ,pp.[PhoneNumber]
    ,pnt.[Name] AS [PhoneNumberType]
    ,ea.[EmailAddress]
    ,p.[EmailPromotion]
    ,a.[AddressLine1]
    ,a.[AddressLine2]
    ,a.[City]
    ,sp.[Name] AS [StateProvinceName] 
    ,a.[PostalCode]
    ,cr.[Name] AS [CountryRegionName] 
    ,p.[AdditionalContactInfo]
FROM [HumanResources].[Employee] e
    INNER JOIN [Person].[Person] p
	ON p.[BusinessEntityID] = e.[BusinessEntityID]
    INNER JOIN [Person].[BusinessEntityAddress] bea 
        ON bea.[BusinessEntityID] = e.[BusinessEntityID] 
    INNER JOIN [Person].[Address] a 
        ON a.[AddressID] = bea.[AddressID]
    INNER JOIN [Person].[StateProvince] sp 
        ON sp.[StateProvinceID] = a.[StateProvinceID]
    INNER JOIN [Person].[CountryRegion] cr 
        ON cr.[CountryRegionCode] = sp.[CountryRegionCode]
    LEFT OUTER JOIN [Person].[PersonPhone] pp
        ON pp.BusinessEntityID = p.[BusinessEntityID]
    LEFT OUTER JOIN [Person].[PhoneNumberType] pnt
        ON pp.[PhoneNumberTypeID] = pnt.[PhoneNumberTypeID]
    LEFT OUTER JOIN [Person].[EmailAddress] ea
        ON p.[BusinessEntityID] = ea.[BusinessEntityID]
WHERE e.BusinessEntityID = 105

Vervolgens inspecteren we de STATISTICS IO en doen we een Vergelijk Showplan . Hoeveel resources heeft een query vanuit een view nodig in vergelijking met query's vanuit basistabellen? Zie figuur 3.

Hier zullen query's vanuit een weergave of basistabellen dezelfde logische leesbewerkingen verbruiken. Beiden gebruikten 19 * 8KB pagina's. Op basis hiervan is het een gelijkspel over wie sneller is. Met andere woorden, het gebruik van een weergave zal de prestaties niet schaden. Laten we het Daadwerkelijke uitvoeringsplan . vergelijken van beide met het Vergelijk Showplan :

Zie je het gearceerde gedeelte van het diagram? Hoe zit het met de QueryPlanHash van beide? Aangezien beide zoekopdrachten gelijk zijn aan QueryPlanHash en dezelfde bewerkingen, weergave- of basistabellen worden op dezelfde manier verwerkt door SQL Server .

Dezelfde logische uitlezingen en hetzelfde plan van het monster vertellen ons dat beide hetzelfde zullen presteren. Als u dus hoge logische waarden heeft, wordt uw query traag, of u nu views gebruikt of niet. Als u dit feit kent, kunt u het probleem oplossen en uw weergave sneller laten verlopen.

Helaas is er slecht nieuws.

SQL-weergaven aan tabellen toevoegen

Wat je eerder zag, is een SELECT uit een weergave zonder joins erin. Maar wat als u zich aan een tafel voegt voor een weergave?

Laten we nog een voorbeeld bekijken. Deze keer gebruiken we de vSalesPerson bekijken in AdventureWorks – een verkoperslijst met contactgegevens en verkoopquota. Nogmaals, we vergelijken de instructie met een SELECT uit basistabellen:

-- get the total sales orders for each salesperson
-- using the view joined with SalesOrderHeader
SELECT 
 sp.FirstName
,sp.MiddleName
,sp.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM Sales.vSalesPerson sp
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY sp.LastName, sp.MiddleName, sp.FirstName

-- using base tables
SELECT
 p.FirstName
,p.MiddleName
,p.LastName
,SUM(soh.TotalDue) AS TotalSalesOrders
FROM sales.SalesPerson sp
INNER JOIN Person.Person p ON sp.BusinessEntityID = P.BusinessEntityID
INNER JOIN Sales.SalesOrderHeader soh ON sp.BusinessEntityID = soh.SalesPersonID
GROUP BY p.LastName, p.MiddleName, p.FirstName 

Als je denkt dat het ook hetzelfde zal zijn, controleer dan de STATISTICS IO:

Verrast? Deelnemen aan de vSalesPerson bekijken met de SalesOrderHeader table heeft enorme resources nodig (28.240 x 8KB) in vergelijking met alleen de basistabellen (774 x 8KB). Merk ook op dat het enkele tabellen bevatte die we niet nodig hadden (de tabellen in rode vakken). Laat staan ​​hogere logische waarden op SalesOrderHeader bij gebruik van de weergave.

Maar daar houdt het niet op.

Het werkelijke uitvoeringsplan onthult meer

Let op het werkelijke uitvoeringsplan van de query om tabellen te baseren:

De afbeelding lijkt een vrij normaal uitvoeringsplan te tonen. Maar kijk eens naar degene met het uitzicht:

Het uitvoeringsplan in figuur 7 valt samen met de STATISTICS IO in figuur 5. Vanuit de view kunnen we de tabellen zien die we niet nodig hebben. Er is ook een Key Lookup knooppunt met een rijschatting die meer dan duizend records verwijderd is dan de werkelijke rijen. Ten slotte verschijnt er ook een waarschuwing in het SELECT-knooppunt. Wat zou het kunnen zijn?

Wat is dat ExcessiveGrant waarschuwing in het SELECT-knooppunt?

Een buitensporige toekenning vindt plaats wanneer het maximaal gebruikte geheugen te klein is in vergelijking met het toegekende geheugen. In dit geval werd 1024 KB toegekend, maar werd er slechts 16 KB gebruikt.

Memory Grant is de geschatte hoeveelheid geheugen in KB die nodig is om het plan uit te voeren.

Het kunnen de verkeerde schattingen zijn in de Key Lookup node en/of het opnemen van de tabellen die we niet nodig hadden in het plan dat dit veroorzaakte. Ook kan te veel toegekend geheugen blokkering veroorzaken. De resterende 1008 KB had nuttig kunnen zijn voor andere bewerkingen.

Uiteindelijk ging er iets mis toen je met een tafel in het zicht kwam. We hoeven deze problemen niet aan te pakken als we vragen vanuit de basistabellen.

Afhaalmaaltijden

Het was een lange uitleg. We weten echter dat views niet worden geëvalueerd of verwerkt VOORDAT een WHERE-component of joins in de outer query worden geëvalueerd. We hebben ook bewezen dat beide hetzelfde zouden presteren.

Aan de andere kant is er een geval waarin we een weergave aan een tafel koppelen. Het gebruikt samenvoegingen van tabellen die we niet nodig hebben vanuit de weergave. Ze zijn voor ons onzichtbaar tenzij we de STATISTICS IO en het Actual Execution Plan controleren. Het kan allemaal de prestaties schaden en problemen kunnen uit het niets komen.

Daarom:

  • We zouden moeten weten hoe zoekopdrachten, inclusief weergaven, van binnenuit werken.
  • STATISTICS IO en Actual Execution Plans zullen onthullen hoe queries en views zullen werken.
  • We kunnen niet zomaar een weergave aan een tafel koppelen en deze achteloos hergebruiken. Controleer altijd de STATISTIEKEN IO en de werkelijke uitvoeringsplannen! In plaats van weergaven opnieuw te gebruiken en te nesten voor "verbeterde" codeerproductiviteit, gebruik ik een IntelliSense en de code-aanvullingstool zoals SQL Complete.

We kunnen er dan zeker van zijn dat we geen views schrijven die de juiste resultaten opleveren, maar als een slak werken.

3. Probeer geïndexeerde weergaven

Geïndexeerde weergaven zijn wat de naam al aangeeft. Het kan een prestatieverbetering geven aan SELECT-instructies. Maar net als tabelindexen kan het de prestaties beïnvloeden als de basistabellen groot zijn en continu worden bijgewerkt.

Laten we eens kijken naar de vStateProvinceCountryRegion om te zien hoe geïndexeerde weergaven de prestaties van zoekopdrachten kunnen verbeteren. bekijken in AdventureWorks . De weergave is geïndexeerd op StateProvinceID en LandRegionCode . Het is een geclusterde, unieke index.

Laten we de STATISTIEKEN IO vergelijken van de weergave die geen index heeft en een index heeft. Hiermee leren we hoeveel pagina's van 8 KB onze SQL Server zal lezen:

De afbeelding laat zien dat het hebben van een index in de vStateProvinceCountryRegion view reduceert logische uitlezingen met de helft. Het is een verbetering van 50% vergeleken met het ontbreken van een index.

Dat is goed om te horen.

Maar nogmaals, voeg geen indexen toe aan uw weergaven achteloos. Naast het hebben van een lange lijst met strikte regels om 1 unieke, geclusterde index te hebben, kan het de prestaties schaden, net zoals het parmantig toevoegen van indexen aan tabellen. Controleer ook de STATISTICS IO als er een afname is in logische uitlezingen na het toevoegen van de index.

Afhaalmaaltijden

Zoals we in ons voorbeeld hebben gezien, kunnen geïndexeerde weergaven de prestaties van de SQL-weergaven verbeteren.

BONUS-tip

Net als elke andere query, zullen SQL-weergaven snel worden uitgevoerd als:

  • Statistieken zijn bijgewerkt
  • Ontbrekende indexen zijn toegevoegd
  • Indexen zijn gedefragmenteerd
  • Indices gebruikten de juiste FILLFACTOR

Conclusie

Zijn SQL-weergaven goed of slecht?

SQL-views zijn goed als we ze correct schrijven en controleren hoe ze worden verwerkt. We hebben tools zoals STATISTICS IO en Actual Execution Plan - gebruik ze! Geïndexeerde weergaven kunnen ook de prestaties verbeteren.

Like deze post? Deel alsjeblieft wat liefde op je favoriete sociale mediaplatform.


  1. Hoe de maxrecursion-optie voor een CTE in een Table-Valued-Function in te stellen?

  2. Negatieve getallen opmaken met punthaken in Oracle

  3. Oracle Database Client stap voor stap installeren

  4. Hoe lange regels tekst in SQLite-resultaten te laten lopen