Database
 sql >> база данни >  >> RDS >> Database

Топ 3 съвета, които трябва да знаете, за да пишете по-бързи SQL изгледи

Приятел или враг? Изгледите на SQL Server бяха обект на разгорещени дебати, когато бях през първата си година, използвайки SQL Server. Казаха, че е лошо, защото е бавно. Но какво ще кажете за днес?

На същата лодка ли сте като мен преди много години? След това се присъединете към мен в това пътуване, за да разгадаете истинската сделка за SQL изгледите, за да можете да ги напишете възможно най-бързо.

SQL изгледите са виртуални таблици. Записите в изгледа са резултат от заявка в него. Всеки път, когато основните таблици, използвани в изгледа, се актуализират, той също актуализира изгледа. В някои случаи можете също да ВМЪКВАТЕ, АКТУАЛИЗИРАТЕ и ИЗТРИВАТЕ записи в изглед като таблица. Въпреки че не съм пробвал това сам.

Подобно на таблица, можете да СЪЗДАВАТЕ, ПРОМЕНЯТЕ или ПУСКАТЕ изглед. Можете дори да създадете индекс, с някои ограничения.

Имайте предвид, че използвах SQL Server 2019 в примерните кодове.

1. Познайте правилното и неправилното използване на SQL изгледи

Първо, основите.

За какво са SQL изгледите?

То е от решаващо значение. Ако го използвате като чук към отвертка, забравете за по-бързите SQL изгледи. Първо, нека си припомним правилната употреба:

  • За фокусиране, опростяване и персонализиране на възприятието, което всеки потребител има за базата данни.
  • За да позволи на потребителите достъп до единствената информация, която трябва да виждат от съображения за сигурност.
  • За да осигурите обратна съвместимост със стара таблица или стара схема, за да не нарушавате зависими приложения. Това е временно, докато не бъдат завършени всички необходими промени.
  • За разделяне на данни, идващи от различни сървъри. Следователно те изглеждат така, сякаш са една таблица от един сървър или инстанция.

Как да НЕ използвате изгледи на SQL Server?

  • Използвайте повторно изгледа в друг изглед, който ще бъде използван повторно в още, друг изглед. Накратко, дълбоко вложени изгледи. Повторната употреба на код има няколко недостатъка в този случай.
  • Спестете при натискане на клавиши. Той се отнася до първия, който намалява натиска на пръста и изглежда ускорява кодирането.

Неправилното използване на изгледи, ако е разрешено, ще затъмни истинската причина, поради която създавате изгледи. Както ще видите по-късно, реалните ползи са по-големи от предполагаемите ползи от неправилната употреба.

Пример

Нека разгледаме пример от Microsoft. vEmployee изглед от AdventureWorks . Ето кода:

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

Целта на този изглед се фокусира върху основната информация за служителите. Ако е необходимо от персонала по човешки ресурси, той може да бъде показан на уеб страница. Използвано ли е повторно в други изгледи?

Опитайте това:

  1. В SQL Server Management Studio , потърсете AdventureWorks база данни.
  2. Разгънете папката Views и потърсете [Човешки ресурси].[vEmployee].
  3. Щракнете с десния бутон върху него и изберете Преглед на зависимости .

Ако видите друг изглед в зависимост от този изглед, който след това зависи от различен изглед, Microsoft ни даде лош пример. Но тогава няма други зависимости от изгледите.

Да преминем към следващото.

2. Развенчайте мита за SQL изгледи

Когато SQL Server обработва SELECT от изглед , той оценява кода в изгледа ПРЕДИ да се занимава с клаузата WHERE или което и да е присъединяване във външната заявка. С повече обединени таблици това ще бъде бавно в сравнение с SELECT от базови таблици със същите резултати.

Поне така ми казаха, когато започнах да използвам SQL. Дали е мит или не, има само един начин да разберете. Нека се обърнем към практически пример.

Как работят SQL изгледите

Microsoft не ни остави на тъмно, за да обсъждаме безкрайно. Имаме инструментите, за да видим как работят заявките, като например СТАТИСТИКА IO и План за действително изпълнение . Ще ги използваме във всички наши примери. Нека вземем първия.

USE AdventureWorks
GO

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

За да видите какво се случва, когато SQL Server обработва изгледа, нека проверим Действителния план за изпълнение на фигура 1. Сравняваме го с кода CREATE VIEW за vEmployee в предишния раздел.

Както можете да видите, първите възли, обработени от SQL Server, са тези, използващи INNER JOIN. След това пристъпва към обработка на LEFT OUTER JOIN.

Тъй като не можем да видим възел на Filter никъде за клаузата WHERE, той трябва да бъде в един от тези възли. Ако проверите свойствата на всички възли, ще видите обработена клауза WHERE в таблицата на служителите. Оградих го в кутия на фигура 1. За да докажете, че е там, вижте фигура 2 за свойствата на този възел:

Анализ

И така, имаше израза SELECT в vEmployee изглед е оценен или обработен ПРЕДИ клаузата WHERE е била приложена? Планът за изпълнение показва, че не е имало. Ако беше, трябва да се появи най-близо до възела SELECT.

Това, което ми казаха, беше мит. Избягвах нещо добро поради неразбиране на правилното използване на SQL изгледи.

Сега, когато знаем как SQL Server обработва SELECT от изглед , остава въпросът:По-бавно ли е, отколкото да не се използва изглед?

ИЗБЕРЕТЕ ОТ изглед спрямо ИЗБЕРЕТЕ ОТ базови таблици – коя ще работи по-бързо?

Първо, трябва да извлечем оператора SELECT вътре в vEmployee прегледайте и произведете същия резултат, който имахме, когато използвахме изгледа. Кодът по-долу показва същата клауза WHERE:

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

След това проверяваме STATISTICS IO и правим Сравнение на шоуплан . Колко ресурси ще са необходими на заявка от изглед в сравнение със заявка от базови таблици? Вижте Фигура 3.

Тук заявките от изглед или базови таблици ще консумират същите логически четения. И двете са използвали 19 * 8KB страници. Въз основа на това е равенство кой е по-бърз. С други думи, използването на изглед няма да навреди на производителността. Нека сравним План за действително изпълнение и от двете, като използвате Сравнете шоуплана :

Виждате ли засенчената част от диаграмата? Какво ще кажете за QueryPlanHash от двете? Тъй като и двете заявки имат равен QueryPlanHash и същите операции, изглед или базови таблици ще бъдат обработени еднакво от SQL Server .

Същите логически показания и един и същи план на извадката ни казват, че и двете ще изпълняват еднакво. По този начин наличието на високо логично четене ще накара заявката ви да се изпълнява бавно, независимо дали използвате изгледи или не. Познаването на този факт ще ви помогне да отстраните проблема и да накарате изгледа ви да работи по-бързо.

За съжаление, има някои лоши новини.

Присъединяване на SQL изгледи към таблици

Това, което видяхте по-рано, е SELECT от изглед без присъединяване в него. Но какво ще стане, ако присъедините таблица към изглед?

Нека разгледаме друг пример. Този път използваме vSalesPerson вижте в AdventureWorks – списък на продавачите с информация за контакт и квота за продажби. Отново сравняваме израза с SELECT от базови таблици:

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

Ако смятате, че също ще бъде същото, проверете СТАТИСТИКА IO:

Изненадан? Присъединяване към vSalesPerson преглед с SalesOrderHeader таблицата се нуждае от огромни ресурси (28,240 x 8KB) в сравнение с използването само на базовите таблици (774 x 8KB). Забележете също, че включваше някои таблици, от които не се нуждаехме (таблиците в червените полета). Да не говорим за по-високи логически показания на SalesOrderHeader когато използвате изгледа.

Но това не свършва дотук.

Реалният план за изпълнение разкрива повече

Забележете действителния план за изпълнение на заявката към базови таблици:

Илюстрацията изглежда показва доста нормален план за изпълнение. Но вижте този с изгледа:

Планът за изпълнение на фигура 7 съвпада със STATISTICS IO на фигура 5. Можем да видим таблиците, от които не се нуждаем, от изгледа. Има и Ключово търсене възел с оценка на ред, която е повече от хиляда записа отклонена от действителните редове. Накрая се появява и предупреждение в възела SELECT. Какво може да бъде?

Какво е това Прекомерен Грант предупреждение във възела SELECT?

Прекомерно предоставяне се случва, когато максимално използваната памет е твърде малка в сравнение с предоставената памет. В този случай бяха предоставени 1024 КБ, но бяха използвани само 16 КБ.

Memory Grant е прогнозното количество памет в KB, необходимо за изпълнение на плана.

Може да са грешни оценки в Ключово търсене възел и/или включването на таблиците, от които не се нуждаехме, в плана, който причини това. Също така, твърде много предоставената памет може да причини блокиране. Останалите 1008 КБ биха могли да са полезни за други операции.

В крайна сметка нещо се обърка, когато се присъединихте към изгледа с маса. Не е нужно да се справяме с тези проблеми, ако правим заявки от базовите таблици.

Вземане за вкъщи

Беше дълго обяснение. Въпреки това, ние знаем, че изгледите не се оценяват или обработват ПРЕДИ клауза WHERE или съединения във външната заявка да бъдат оценени. Доказахме също, че и двете ще се представят еднакво.

От друга страна, има случай, когато присъединяваме изглед към маса. Той използва съединения на таблици, от които не се нуждаем от изгледа. Те са невидими за нас, освен ако не проверим STATISTICS IO и действителния план за изпълнение. Всичко това може да навреди на производителността и проблемите могат да дойдат от нищото.

Следователно:

  • Трябва да знаем как заявките, включително изгледите, работят отвътре.
  • СТАТИСТИЧЕСКИ IO и действителните планове за изпълнение ще разкрият как ще работят заявките и изгледите.
  • Не можем просто да присъединим изглед към таблица и да го използваме повторно небрежно. Винаги проверявайте СТАТИСТИКАТА IO и действителните планове за изпълнение! Вместо да използвам повторно изгледи и да ги влагам за „подобрена“ производителност на кодиране, използвам IntelliSense и инструмента за завършване на код като SQL Complete.

Тогава можем да сме сигурни, че няма да пишем изгледи, които ще имат правилни резултати, но ще работят като охлюв.

3. Опитайте индексирани изгледи

Индексираните изгледи са това, което подсказва името. Може да повиши производителността на операторите SELECT. Но подобно на индексите на таблици, това може да повлияе на производителността, ако основните таблици са големи и непрекъснато се актуализират.

За да видите как индексираните изгледи могат да подобрят ефективността на заявката, нека да разгледаме vStateProvinceCountryRegion вижте в AdventureWorks . Изгледът се индексира на StateProvinceID и CountryRegionCode . Това е клъстериран, уникален индекс.

Нека сравним STATISTICS IO на изгледа, който няма индекс и има индекс. С това научаваме колко 8KB страници ще прочете нашия SQL сървър:

Фигурата показва, че наличието на индекс в vStateProvinceCountryRegion view намалява логическите четения наполовина. Това е 50% подобрение в сравнение с липсата на индекс.

Приятно е да се чуе.

И все пак, отново, не добавяйте индекси към изгледите си небрежно. Освен че има дълъг списък от строги правила, за да има 1 уникален, клъстериран индекс, това може да навреди на производителността, подобно на добавянето на индекси към таблиците. Също така, проверете STATISTICS IO, ако има спад в логическите четения след добавяне на индекса.

Вземане за вкъщи

Както видяхме в нашия пример, индексираните изгледи могат да подобрят производителността на SQL изгледите.

БОНУС съвет

Както всяка друга заявка, SQL изгледите ще работят бързо, ако:

  • Статистиката се актуализира
  • Добавят се липсващи индекси
  • Индексите са дефрагментирани
  • Индексите са използвали правилния FILLFACTOR

Заключение

SQL изгледите добри или лоши ли са?

SQL изгледите са добри, ако ги напишем правилно и проверим как ще бъдат обработени. Имаме инструменти като STATISTICS IO и Actual Execution Plan – използвайте ги! Индексираните изгледи също могат да подобрят производителността.

Харесвате ли тази публикация? Моля, споделете малко любов в любимата си платформа за социални медии.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Визуализирайте повратната точка с Plan Explorer

  2. Брой на SQL

  3. Може ли ColumnStore да помогне за работните натоварвания с пагинация?

  4. Моля, помогнете с STRING_SPLIT подобрения

  5. Разберете ролята на архитектите на данни в управлението на данните