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

Всичко, което трябва да знаете за SQL CTE на едно място

Първият път, когато Карл чу за SQL Server CTE, беше, когато търсеше нещо, което да направи своя SQL код по-лесен за окото. Това е нещо като главоболие, когато го гледаш. Антон, негов загрижен колега, го попита за CTE. Карл помисли, че Антон има предвид главоболието си. Може би е чул всичко погрешно, така че той отговори:„Разбира се, че не“. Забавното е, че той имаше предвид хронична травматична енцефалопатия, също CTE – невродегенеративно заболяване, причинено от повтарящи се наранявания на главата. Но въз основа на отговора на Карл Антон знаеше със сигурност, че неговият колега не знае какво казва.

Какъв луд начин за въвеждане на CTEs! И така, преди да влезете в същата лодка, нека изясним какво е SQL CTE или общи изрази на таблица в света на SQL?

Можете да прочетете основите тук. Междувременно ще научим малко повече за случилото се в тази необичайна история.

4 Основни неща за CTE в SQL Server

„Един SQL CTE има име“

Антон започна с идеята, че SQL CTE са временно именувани набори от резултати. Като временно средство, CTE е ограничен по обхват.

„И така, това е като подзаявка?“ — попита Карл.

„В известен смисъл, да. Но не можете да назовете подзаявка“, каза Антон. „CTE има име, подобно на таблица с име. Въпреки това, вместо CREATE, вие използвате WI, за да го създадете. След това той написа синтаксиса на хартия:

WITH <cte_name>(<column list>)
AS
(
<inner query defining the CTE>
)
<outer query against CTE>

„CTE е изчезнал, когато SELECT е готово“

Антон продължи, като обясни обхвата на SQL CTE.

„Временна таблица може да съществува в обхвата на процедурата или глобално. Но CTE го няма, когато SELECT приключи“, каза той с рима. „Същото нещо, ако го използвате за INSERT, UPDATE или DELETE“, продължи той.

„Не можете да го използвате повторно“

„За разлика от изглед или временна таблица, не можете да използвате повторно SQL CTE. Името е там, така че можете да се обърнете към него във вътрешната и външната заявка. Но това е всичко“, каза Антон.

„И така, какво е голямото за SQL CTEs?“ — попита Карл.

„Можете да направите кода си по-четлив“

— Голямата работа? Антон отговори на въпроса. „Това е, че можете да направите кода си лесно четим. Не е ли това, което търсите?”

„Точно така“, призна Карл.

И така, каква е следващата логична стъпка, която трябва да направи Карл?

Допълнителни неща за CTE в SQL

На следващия ден Карл продължи търсенето на SQL CTE. Освен горното, ето какво откри:

  • SQL CTE може да бъде нерекурсивен или рекурсивен.
  • Не само SQL Server, но и MySQL и Oracle подкрепят идеята. Всъщност това е част от спецификациите на SQL-99.
  • Докато се използва за опростяване на SQL кода, той не подобрява производителността.
  • И също така няма да замени подзаявките и временните таблици. Всеки има своето място и приложение.

Накратко, това е друг начин за изразяване на заявка .

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

Какво ще работи в SQL Server CTE?

Копайки по-нататък, за да разгадае повече за CTE, Карл изброи по-долу какво би приел SQL Server. Погледнете и следването му.

Задаване на вградени или външни псевдоними на колони

SQL CTE поддържат две форми на присвояване на псевдоними на колони. Първият е вграденият формуляр, като примера по-долу:

-- Use an Inline column alias

USE AdventureWorks
GO;

WITH Sales_CTE
AS  
(  
	SELECT SalesPersonID, COUNT(*) AS NumberOfOrders
	FROM Sales.SalesOrderHeader  
	WHERE SalesPersonID IS NOT NULL  
	GROUP BY SalesPersonID  
)
SELECT
 a.SalesPersonID
,a.NumberOfOrders
FROM Sales_CTE a

Горният код използва псевдоним на колона в дефиницията на CTE, когато се присвоява в оператора SELECT. Забелязахте ли COUNT(*) AS NumberOfOrders ? Това е вграденият формуляр.

Сега, друг пример е външната форма:

-- Use an external column alias

USE AdventureWorks
GO;

WITH Sales_CTE(SalesPersonID, NumberOfOrders) 
AS  
(  
	SELECT SalesPersonID, COUNT(*)
	FROM Sales.SalesOrderHeader  
	WHERE SalesPersonID IS NOT NULL  
	GROUP BY SalesPersonID  
)
SELECT
 a.SalesPersonID
,a.NumberOfOrders
FROM Sales_CTE a

Колоните могат да бъдат дефинирани и в скоби след задаване на името на CTE. Забележете WITH Sales_CTE (SalesPersonID, NumberOfOrders) .

CTE в SQL предхожда SELECT, INSERT, UPDATE или DELETE

Следващият елемент е за консумацията на CTE. Първият и често срещан пример е, когато предхожда оператор SELECT.

-- List down all Salespersons with their all-time number of orders
USE AdventureWorks
GO;

WITH Sales_CTE (SalesPersonID, NumberOfOrders)  
AS  
(  
	SELECT SalesPersonID, COUNT(*)  
	FROM Sales.SalesOrderHeader  
	WHERE SalesPersonID IS NOT NULL  
	GROUP BY SalesPersonID  
)
SELECT
 a.SalesPersonID
,CONCAT(P.LastName,', ',P.FirstName,' ',P.MiddleName) AS SalesPerson
,a.NumberOfOrders
FROM Sales_CTE a
INNER JOIN Person.Person p ON a.SalesPersonID = p.BusinessEntityID

Какво показва този пример?

  • Продажби_CTE – името на CTE.
  • (SalesPersonID, NumberOfOrders) – дефиницията на CTE колони.
  • ИЗБЕРЕТЕ SalesPersonID, COUNT(*) ОТ Sales.SalesOrderHeader, КЪДЕ SalesPersonID НЕ Е NULL ГРУПА ПО SalesPersonID – вътрешният SELECT, който дефинира CTE.
  • ИЗБЕРЕТЕ a.SalesPersonID, CONCAT(P.LastName,’, ‘,P.FirstName,’ ‘,P.MiddleName) КАТО SalesPerson – външната заявка, която консумира CTE. Този пример използва SELECT за консумиране на CTE.
  • ОТ Sales_CTE a – препратката на външната заявка към CTE.

Освен SELECT, той работи и с INSERT, UPDATE и DELETE. Ето пример за използване на INSERT:

-- add a 10% increase to Employee 16 after 1 year from the previous increase.
USE AdventureWorks
GO;

WITH LatestEmployeePay
AS
(
    SELECT TOP 1
     eph.BusinessEntityID
    ,eph.RateChangeDate
    ,eph.Rate
    ,eph.PayFrequency
    FROM HumanResources.EmployeePayHistory eph 
    WHERE eph.BusinessEntityID = 16
    ORDER BY eph.RateChangeDate DESC
)
INSERT INTO HumanResources.EmployeePayHistory
SELECT
 BusinessEntityID
,DATEADD(d,365,RateChangeDate)
,(Rate * 0.1) + Rate
,PayFrequency
,GETDATE()
FROM LatestEmployeePay

В горния списък CTE извлича последното заплащане за служител 16. След това резултатният набор на CTE се използва за вмъкване на нов запис в EmployeePayHistory . Карл записа елегантно своите открития. Освен това той използва подходящи примери.

Дефинирайте множество CTE в 1 заявка

Това е вярно. Карл установи, че множество CTE са възможни в 1 заявка. Ето един пример:

-- Get the present and previous rate of employee 16
USE AdventureWorks
GO;

WITH LatestEmployeePay
AS
(
    SELECT TOP 1
     eph.BusinessEntityID
    ,eph.RateChangeDate
    ,eph.Rate
    FROM HumanResources.EmployeePayHistory eph 
    WHERE eph.BusinessEntityID = 16
    ORDER BY eph.RateChangeDate DESC
),
PreviousEmployeePay AS
(
    SELECT TOP 1
     eph.BusinessEntityID
    ,eph.RateChangeDate
    ,eph.Rate
    FROM HumanResources.EmployeePayHistory eph
    INNER JOIN LatestEmployeePay lep 
      ON eph.BusinessEntityID = lep.BusinessEntityID
    WHERE eph.BusinessEntityID = 16
      AND eph.RateChangeDate < lep.RateChangeDate
    ORDER BY eph.RateChangeDate DESC
)
SELECT
 a.BusinessEntityID
,a.Rate
,a.RateChangeDate
,b.Rate AS PreviousRate
FROM LatestEmployeePay a
INNER JOIN PreviousEmployeePay b 
    ON a.BusinessEntityID = b.BusinessEntityID

Горният код използва 2 CTE в една заявка, а именно LatestEmployeePay и PreviousEmployeePay .

Вижте CTE многократно

Има още за предишния пример. Забележете също, че можете ВЪТРЕШНО ПРИСЪЕДИНЯВАНЕ на първия CTE към втория CTE. И накрая, външната заявка може да се присъедини към двата CTE. LatestEmployeePay е споменат два пъти.

Предаване на аргументи към SQL CTE

Аргументи, като променливи, могат да се предават по CTE:

DECLARE @SalesPersonID INT = 275;

WITH Sales_CTE
AS  
(  
	SELECT SalesPersonID, COUNT(*) AS NumberOfOrders
	FROM Sales.SalesOrderHeader 
	WHERE SalesPersonID = @SalesPersonID  
	GROUP BY SalesPersonID  
)  
SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE

Горният код започва с деклариране и задаване на променлива @SalesPersonID . След това стойността се предава на CTE, за да филтрира резултата.

Използвайте в КУРСОР

SQL курсорът може да използва израз SELECT и да преглежда резултатите. Също така, SQL CTE може да се използва с него:

DECLARE @SalesPersonID INT
DECLARE @NumberofOrders INT

DECLARE sales_cursor CURSOR FOR
    WITH Sales_CTE (SalesPersonID, NumberOfOrders)  
	AS  
	(  
		SELECT SalesPersonID, COUNT(*)  
		FROM Sales.SalesOrderHeader  
		WHERE SalesPersonID IS NOT NULL  
		GROUP BY SalesPersonID  
	)  
	SELECT salespersonid, numberoforders
	FROM Sales_CTE; 
OPEN sales_cursor
FETCH NEXT FROM sales_cursor INTO @SalesPersonID, @NumberofOrders
WHILE @@FETCH_STATUS = 0  
BEGIN
	PRINT 'SalesPersonID: ' + CAST(@SalesPersonID AS VARCHAR)
	PRINT '# of Orders: ' + CAST(@NumberofOrders AS VARCHAR)
	FETCH NEXT FROM sales_cursor  INTO @SalesPersonID, @NumberofOrders
END
CLOSE sales_cursor
DEALLOCATE sales_cursor;

Използвайте временна таблица в рекурсивна CTE

Рекурсивният CTE използва закотвен член и рекурсивен член в дефиницията на CTE. Помага за получаване на йерархии в таблица. SQL CTE може да използва и временна таблица за тази цел. Вижте пример по-долу:

-- Create a Crew table.  
CREATE TABLE #EnterpriseDSeniorOfficers  
(  
CrewID SMALLINT NOT NULL,  
FirstName NVARCHAR(30)  NOT NULL,  
LastName  NVARCHAR(40) NOT NULL,  
CrewRank NVARCHAR(50) NOT NULL,  
HigherRankID INT NULL,  
 CONSTRAINT PK_CrewID PRIMARY KEY CLUSTERED (CrewID ASC)   
);  
-- Populate the table with values.  
INSERT INTO #EnterpriseDSeniorOfficers VALUES   
 (1, N'Jean-Luc', N'Picard', N'Captain',NULL)  
,(2, N'William', N'Riker', N'First Officer',1)  
,(3, N'Data', N'', N'Second Officer',1)  
,(4, N'Worf', N'', N'Chief of Security',1)  
,(5, N'Deanna', N'Troi', N'Ship Counselor',1)  
,(6, N'Beveryly', N'Crusher', N'Chief Medical Officer',1)  
,(7, N'Geordi', N'LaForge', N'Chief Engineer',1);  

WITH DirectReports(HigherRankID, CrewID, Title, CrewLevel) AS   
(  
    SELECT HigherRankID, CrewID, CrewRank, 0 as CrewLevel
    FROM #EnterpriseDSeniorOfficers
    WHERE HigherRankID IS NULL  
    UNION ALL  
    SELECT e.HigherRankID, e.CrewID, e.CrewRank, CrewLevel + 1  
    FROM #EnterpriseDSeniorOfficers AS e  
        INNER JOIN DirectReports AS d  
        ON e.HigherRankID = d.CrewID   
)  
SELECT HigherRankID, CrewID, Title, CrewLevel   
FROM DirectReports  
OPTION (MAXRECURSION 2)
ORDER BY HigherRankID;  

DROP TABLE #EnterpriseDSeniorOfficers

Карл обясни чрез дисекция на този CTE. Ето как става.

Закотвеният член е първият оператор SELECT с нулево (0) ниво на екипажа:

SELECT HigherRankID, CrewID, CrewRank, 0 as CrewLevel
 FROM #EnterpriseDSeniorOfficers
 WHERE HigherRankID IS NULL

Този закотвен член получава основния възел на йерархията. Клаузата WHERE указва, че основното ниво (HigherRankID IS NULL ).

Рекурсивният член, който ще получи дъщерните възли, се извлича по-долу:

SELECT e.HigherRankID, e.CrewID, e.CrewRank, CrewLevel + 1  
FROM #EnterpriseDSeniorOfficers AS e  
INNER JOIN DirectReports AS d  
        ON e.HigherRankID = d.CrewID

Има и ОПЦИЯ (МАКС. РЕКУРСИЯ 2) използвани във външната заявка. Рекурсивните CTE могат да станат проблематични, когато в резултат на рекурсивната заявка се получава безкраен цикъл. MAXRECURSION 2 избягва тази бъркотия – ограничава цикъла само до 2 рекурсии.

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

Какво няма да работи в SQL CTE?

Тук имаме списък с неща, които ще генерират грешка при използване на SQL CTE.

Без точка и запетая пред SQL CTE

Ако има изявление преди CTE, то трябва да бъде завършено с точка и запетая. Клаузата WITH може да работи за други цели, като в табличен намек, като по този начин точката и запетаята ще премахне неяснотата. Посоченото по-долу изявление ще доведе до грешка:

DECLARE @SalesPersonID INT

SET @SalesPersonID = 275

WITH Sales_CTE
AS  
(  
	SELECT SalesPersonID, COUNT(*) AS NumberOfOrders
	FROM Sales.SalesOrderHeader 
	WHERE SalesPersonID = @SalesPersonID  
	GROUP BY SalesPersonID  
)  
SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE

За първи път, които не са прекратявали изрази с точка и запетая, срещат тази грешка:

Колони без име

„Забравихте да поставите псевдоним на колона? Тогава ви предстои още една грешка." Карл каза това в своя документ и също така предостави примерен код, който споделям по-долу:

DECLARE @SalesPersonID INT

SET @SalesPersonID = 275;

WITH Sales_CTE
AS  
(  
	SELECT SalesPersonID, COUNT(*)
	FROM Sales.SalesOrderHeader 
	WHERE SalesPersonID = @SalesPersonID  
	GROUP BY SalesPersonID  
)  
SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE

След това вижте съобщението за грешка:

Дублиращи се имена на колони

Друга грешка, свързана с #2 по-горе, е използването на същото име на колона в CTE. Можете да се разминете с него в нормален оператор SELECT, но не и с CTE. Карл имаше друг пример:

WITH Sales_CTE
AS  
(  
	SELECT SalesPersonID AS col1, COUNT(*) AS col1
	FROM Sales.SalesOrderHeader 
	GROUP BY SalesPersonID  
)  
SELECT *
FROM Sales_CTE

Клауза ПОРЪЧВАНЕ ПО БЕЗ ВЪРХА или ОТМЕСТВАНЕ-ИЗВЪРШВАНЕ

Стандартният SQL не позволява ORDER BY в таблични изрази, когато го използваме за сортиране на резултантните набори. Въпреки това, ако се използва TOP или OFFSET-FETCH, ORDER BY става помощно средство за филтриране.

Ето примера на Карл, използващ ORDER BY:

WITH LatestEmployeePay
AS
(
    SELECT
     eph.BusinessEntityID
    ,eph.RateChangeDate
    ,eph.Rate
    ,eph.PayFrequency
    FROM HumanResources.EmployeePayHistory eph 
    WHERE eph.BusinessEntityID = 16
    ORDER BY eph.RateChangeDate DESC
)
INSERT INTO HumanResources.EmployeePayHistory
SELECT
 BusinessEntityID
,DATEADD(d,365,RateChangeDate)
,(Rate * 0.1) + Rate
,PayFrequency
,GETDATE()
FROM LatestEmployeePay

Забележете, че това е същият пример, който имахме по-рано, но този път TOP не е посочен. Вижте грешката:

Броят на колоните не е същият като определението на списъка с колони

Карл използва същия рекурсивен пример за CTE, но извади колона в анкерния член:

WITH DirectReports(HigherRankID, CrewID, Title, CrewLevel) AS   
(  
    SELECT HigherRankID, CrewID
    FROM #EnterpriseDSeniorOfficers
    WHERE HigherRankID IS NULL  
    UNION ALL  
    SELECT e.HigherRankID, e.CrewID, e.CrewRank, CrewLevel + 1  
    FROM #EnterpriseDSeniorOfficers AS e  
        INNER JOIN DirectReports AS d  
        ON e.HigherRankID = d.CrewID   
)  
SELECT HigherRankID, CrewID, Title, CrewLevel   
FROM DirectReports  
ORDER BY HigherRankID;

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

Други неща, които не са разрешени в CTE

Освен списъка по-горе, ето още няколко от констатациите на Карл, които предизвикват грешки, ако го използвате по погрешка в SQL CTE.

  • Използване на клауза SELECT INTO, OPTION със съвети за заявка и използване на FOR BROWSE.
  • Различни данни и типове в колоните за закотвен член в сравнение с колоните с рекурсивни членове.
  • Имайки следните ключови думи в рекурсивен член на рекурсивна CTE:
    • ГОРЕ
    • ВЪНШНО ПРИСЪЕДИНЯВАНЕ (Но ВЪТРЕШНО ПРИЕДИНЕНИЕ е разрешено)
    • ГРУПИРАНЕ ПО и ПРИЕМАНЕ
    • Подзаявки
    • ИЗБЕРЕТЕ ДИСТАНЦИОННО
  • Използване на скаларно агрегиране.
  • Използване на подзаявки в рекурсивен член.
  • Да има вложени SQL CTE.

SQL CTE срещу временни таблици срещу подзаявки

Понякога можете да пренапишете SQL CTE, като използвате подзаявка. Също така, понякога можете да разбиете SQL CTE, като използвате временни таблици от съображения за производителност. Както всяка друга заявка, трябва да проверите действителния план за изпълнение и STATISTICS IO, за да знаете коя опция да вземете. SQL CTE може да е приятен за очите, но ако ударите стена за производителност, използвайте друга опция . Никоя опция не е по-бърза от другата.

Нека разгледаме три запитвания от документите на Карл, които дават едни и същи резултати. Единият използва SQL CTE, другият използва подзаявка, а третият използва временна таблица. За простота Карл използва малък набор от резултати.

Кодът и ResultSet

Започна с използване на множество SQL CTE.

WITH LatestEmployeePay
AS
(
    SELECT TOP 1
     eph.BusinessEntityID
    ,eph.RateChangeDate
    ,eph.Rate
    FROM HumanResources.EmployeePayHistory eph 
    WHERE eph.BusinessEntityID = 16
    ORDER BY eph.RateChangeDate DESC
),
PreviousEmployeePay AS
(
    SELECT TOP 1
     eph.BusinessEntityID
    ,eph.RateChangeDate
    ,eph.Rate
    FROM HumanResources.EmployeePayHistory eph
    INNER JOIN LatestEmployeePay lep 
        ON eph.BusinessEntityID = lep.BusinessEntityID
    WHERE eph.BusinessEntityID = 16
        AND eph.RateChangeDate < lep.RateChangeDate
    ORDER BY eph.RateChangeDate DESC
)
SELECT
 a.BusinessEntityID
,a.Rate
,a.RateChangeDate
,b.Rate AS PreviousRate
FROM LatestEmployeePay a
INNER JOIN PreviousEmployeePay b 
    ON a.BusinessEntityID = b.BusinessEntityID

Следващата е подзаявка. Както забелязвате, CTE изглежда модулен и четим, но подзаявката по-долу е по-кратка:

SELECT TOP 1
 eph.BusinessEntityID
,eph.Rate
,eph.RateChangeDate
,(SELECT TOP 1 eph1.Rate FROM HumanResources.EmployeePayHistory eph1
  WHERE eph1.BusinessEntityID=16
    AND eph1.RateChangeDate < eph.RateChangeDate
  ORDER BY eph1.RateChangeDate DESC) AS PreviousRate
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC;

Карл също се опита да го раздели на малки парчета код и след това да комбинира резултатите с помощта на временни таблици.

SELECT TOP 1
 eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
INTO #LatestPay
FROM HumanResources.EmployeePayHistory eph 
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC

SELECT TOP 1
 eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
INTO #PreviousPay
FROM HumanResources.EmployeePayHistory eph
INNER JOIN #LatestPay lep 
    ON eph.BusinessEntityID = lep.BusinessEntityID
WHERE eph.BusinessEntityID = 16
    AND eph.RateChangeDate < lep.RateChangeDate
ORDER BY eph.RateChangeDate DESC

SELECT
 a.BusinessEntityID
,a.Rate
,a.RateChangeDate
,b.Rate AS PreviousRate
FROM #LatestPay a
INNER JOIN #PreviousPay b 
    ON a.BusinessEntityID = b.BusinessEntityID

DROP TABLE #LatestPay
DROP TABLE #PreviousPay

Вижте резултатите от тези три начина за получаване на текущите и предишни заплащания за служител 16. Те са еднакви:

Логическите четения

Какво консумира най-много ресурси на SQL Server? Нека да разгледаме СТАТИСТИКА IO. Карл използва statisticsparser.com, за да форматира добре резултатите – добре за нас.

Фигура 7 показва логически показания на използване на CTE спрямо използване на подзаявка:

След това вижте общите логически показания, когато разбиете кода на малки парчета с помощта на временни таблици:

И така, какво консумира повече ресурси? Карл ги класира за по-голяма яснота.

  1. Подзаявка – 4 логически четения (ПОБЕДИТЕЛ!).
  2. SQL CTE – 6 логически четения.
  3. Временни таблици – 8 логически четения.

В този пример най-бързата ще бъде подзаявката.

Реалният план за изпълнение

За да разбере логическите показания, които получихме от STATISTICS IO, Карл също провери действителния план за изпълнение. Той започна от CTE:

Можем да наблюдаваме няколко неща от този план:

  • LatestEmployeePay CTE беше оценен два пъти, когато се използва във външната заявка и когато се присъедини към PreviousEmployeePay . И така, виждаме 2 ТОП възела за това.
  • Виждаме PreviousEmployeePay оценено веднъж.

След това погледнете действителния план за изпълнение на заявката с подзаявка:

Тук има няколко очевидни неща:

  • Планът е по-опростен.
  • По-лесно е, защото подзаявката за получаване на последното заплащане се оценява само веднъж.
  • Нищо чудно, че логическите показания са по-малко в сравнение с логическите четения на заявката с CTE.

И накрая, ето действителния план за изпълнение, когато Карл е използвал временни таблици:

Тъй като това е партида от три изявления, виждаме и три диаграми в плана. И трите са прости, но колективният план не е толкова прост, колкото планът на заявката с подзаявката.

Статистика за времето

Използвайки решението dbForge Studio за SQL Server, можете да сравните статистическите данни за времето в Query Profiler. За това задръжте клавиша CTRL и щракнете върху имената на резултатите на всяка заявка в историята на изпълнението:

Статистиката за времето е в съответствие с логическите показания и действителния план за изпълнение. Подзаявката се изпълняваше най-бързо (88 мс). Това е последвано от CTE (199ms). Последното е използването на временни таблици (536ms).

И така, какво научихме от Карл?

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

Винаги проверявайте STATISTICS IO и действителните планове за изпълнение, за да знаете коя техника да използвате.

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

Надявам се, че не сте се ударили с главата си в стената, за да разберете какво е CTE (Common Table Expressions). В противен случай може да получите CTE (хронична травматична енцефалопатия). Шегата настрана, какво разкрихме?

  • Общите изрази за таблици са временно именувани резултативни набори. По поведение и обхват е по-близо до подзаявка, но по-ясна и по-модуларна. Има и име.
  • SQL CTE е за опростяване на кода, а не за ускоряване на заявката ви.
  • Седем неща, които научихме, ще работят върху SQL CTE.
  • Пет неща ще предизвикат грешка.
  • Също така още веднъж потвърдихме, че СТАТИСТИЧЕСКИЯТ IO и действителният план за изпълнение винаги ще ви дават по-добра преценка. Вярно е, ако сравните CTE с подзаявка и пакет, използвайки временни таблици.

Насладих се? След това бутоните на социалните медии чакат да бъдат натиснати. Изберете любимия си и споделете любовта!

Прочетете също

Как CTE може да помогне при писане на сложни, мощни заявки:Перспектива на производителността


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Google BigQuery ODBC драйвер

  2. SQL NOT оператор за начинаещи

  3. Проектиране на модел на данни за система за резервиране на хотелски стаи

  4. Сравняване на SQL, конструктори на заявки и ORM

  5. Как работи MapReduce в Hadoop