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

Сортирани ли сте? Съвети относно подреждането на прозорци в T-SQL

Поддържащият индекс може потенциално да помогне да се избегне необходимостта от изрично сортиране в плана на заявката при оптимизиране на T-SQL заявки, включващи функции на прозореца. Чрез поддържащ индекс, Имам предвид един с елементите за разделяне и подреждане на прозореца като индексен ключ, а останалите колони, които се появяват в заявката като колони, включени в индекса. Често наричам такъв модел на индексиране POC индекс като акроним за разделяне , поръчване, и покриване . Естествено, ако елемент за разделяне или подреждане не се появи във функцията на прозореца, вие пропускате тази част от дефиницията на индекса.

Но какво да кажем за заявките, включващи множество функции на прозореца с различни нужди за подреждане? По същия начин, какво ще стане, ако други елементи в заявката освен функциите на прозореца също изискват подреждане на входните данни, както е подредено в плана, като например клауза ORDER BY за презентация? Това може да доведе до необходимостта от обработка на входните данни в различни части на плана в различни редове.

При такива обстоятелства обикновено приемате, че изричното сортиране е неизбежно в плана. Може да откриете, че синтактичното подреждане на изразите в заявката може да повлияе на колко изрични оператори за сортиране, които получавате в плана. Като следвате някои основни съвети, понякога можете да намалите броя на операторите за изрично сортиране, което, разбира се, може да окаже голямо влияние върху производителността на заявката.

Среда за демонстрации

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

Пуснах всички примери на SQL Server 2019 Developer, където е наличен пакетен режим в rowstore.

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

SQL Server понастоящем не поддържа ефективна комбинация от паралелен вход за запазване на реда преди оператора Window Aggregate в паралелен пакетен режим. Така че, за да използва паралелен оператор на пакетен режим Window Aggregate, оптимизаторът трябва да инжектира междинен оператор за сортиране в паралелен пакетен режим, дори когато входът вече е предварително поръчан.

За простота можете да предотвратите паралелизъм във всички примери, показани в тази статия. За да постигнете това, без да е необходимо да добавяте намек към всички заявки и без да задавате опция за конфигурация за целия сървър, можете да зададете опцията за конфигурация в обхвата на базата данни MAXDOP до 1 , така:

ИЗПОЛЗВАЙТЕ PerformanceV5; ПРОМЕНИ КОНФИГУРАЦИЯ ЗА ОБХВАТ НА БАЗА ДАННИ MAXDOP =1;

Не забравяйте да го върнете на 0, след като приключите с тестването на примерите в тази статия. Ще ви напомня в края.

Като алтернатива можете да предотвратите паралелизъм на ниво сесия с недокументирания DBCC OPTIMIZER_WHATIF команда, така:

DBCC OPTIMIZER_WHATIF(CPU, 1);

За да нулирате опцията, когато сте готови, я извикайте отново със стойността 0 като брой процесори.

Когато приключите с изпробването на всички примери в тази статия с деактивиран паралелизъм, препоръчвам да активирате паралелизма и да опитате всички примери отново, за да видите какво се променя.

Съвети 1 и 2

Преди да започна със съветите, нека първо разгледаме прост пример с функция на прозорец, предназначена да се възползва от supp class="border indent shadow orting index.

Помислете за следната заявка, която ще наричам Заявка 1:

ИЗБЕРЕТЕ идентификатор на поръчка, дата на поръчка, custid, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum1 ОТ dbo.Orders;

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

Следвайки схемата за индексиране на POC, създавате следния индекс, за да поддържате заявката:

СЪЗДАВАЙТЕ УНИКАЛЕН НЕКЛУСТРИРАН ИНДЕКС idx_nc_cid_od_oid НА dbo.Orders(custid, orderdate, orderid);

Планът за тази заявка е показан на фигура 1.

Фигура 1:План за заявка 1

Тук няма изненади. Планът прилага сканиране на реда на индекса на индекса, който току-що създадохте, като предоставя подредените данни на оператора Window Aggregate, без да е необходимо изрично сортиране.

След това помислете за следната заявка, която включва множество функции на прозореца с различни нужди за подреждане, както и клауза ORDER BY за презентация:

SELECT orderid, orderdate, custid, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕН ПРЕДШЕСТВАЩ) КАТО sum2, SUM(orderid) OVER(PARTITION BY custid ORDER BY дата на поръчка, подреден идентификатор КАТО РЕДОВ ПРЕДВАРИТЕЛЕН, НЕОБЪЕДИНЕН) SUM(1.0 * orderid) OVER(ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum3 ОТ dbo.OrdersORDER BY custid, orderid;

Ще наричам тази заявка заявка 2. Планът за тази заявка е показан на фигура 2.

Фигура 2:План за заявка 2

Забележете, че в плана има четири оператора за сортиране.

Ако анализирате различните функции на прозорците и нуждите за подреждане на презентации, ще откриете, че има три различни нужди за поръчка:

  • custid, orderdate, orderid
  • поръчан
  • custid, orderid

Като се има предвид, че един от тях (първият в списъка по-горе) може да се поддържа от индекса, който сте създали по-рано, бихте очаквали да видите само два вида в плана. И така, защо планът има четири вида? Изглежда, че SQL Server не се опитва да бъде твърде сложен с пренареждането на реда на обработка на функциите в плана, за да минимизира сортирането. Той обработва функциите в плана в реда, в който се появяват в заявката. Поне така е при първото появяване на всяка отделна нужда от поръчка, но скоро ще разкажа за това.

Можете да премахнете необходимостта от някои от видовете в плана, като приложите следните две прости практики:

Съвет 1:Ако имате индекс, който поддържа някои от функциите на прозореца в заявката, първо ги посочете.

Съвет 2:Ако заявката включва функции на прозореца със същата нужда от подреждане като подреждането на презентацията в заявката, посочете тези функции последни.

Следвайки тези съвети, вие пренареждате реда на появяване на функциите на прозореца в заявката по следния начин:

ИЗБЕРЕТЕ идентификатор на поръчка, дата на поръчка, custid, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid ROWS НЕОГРАНИЧЕН ПРЕДШЕСТВУВАЩ) КАТО sum1, SUM(1.0 * orderid) НАД (РЕД BY orderid РЕДОВЕ РЕДОВЕ НЕОГРАНИЧЕНИ sum3 PRECEDING) (orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum2 FROM dbo.OrdersORDER BY custid, orderid;

Ще наричам тази заявка Заявка 3. Планът за тази заявка е показан на Фигура 3.

Фигура 3:План за заявка 3

Както можете да видите, сега планът има само два вида.

Съвет 3

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

Разгледайте следната заявка като пример:

ИЗБЕРЕТЕ идентификатор на поръчка, дата на поръчка, custid, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid ROWS НЕОГРАНИЧЕН ПРЕДШЕСТВУВАЩ) КАТО sum1, SUM(1.0 * orderid) НАД (РЕД BY orderid РЕДОВЕ РЕДОВЕ НЕОГРАНИЧЕНИ sum3 PRECEDING) (поръчков идентификатор) НАД(ДЯЛ ПО custid ORDER BY orderid ROWS НЕОГРАНИЧЕН ПРЕДШЕСТВЕН) КАТО sum2, MAX(orderid) OVER(PARTITION BY custid ORDER BY дата на поръчка, идентификатор на поръчката РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО max1, MAXID(orderid) PRECEDING) КАТО max3, MAX(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕН ПРЕДИШЕН) AS max2, AVG(orderid) OVER(PARTITION BY custid ORDER BY дата на поръчка, orderid ROWS НЕОГРАНИЧЕН ПРЕДИШЕН идентификатор, *AV ) НАД(ПОРЪЧКА ПО РЕДОВ ИД РЕДОВ НЕОГРАНИЧЕН ПРЕДШЕСТВУВАЩ) КАТО avg3, AVG(orderid) НАД (РАЗДЕЛЯНЕ ПО custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) AS avg2 FROM dbo.OrdersORDER BY custid, orderid;
>

Ще наричам тази заявка заявка 4. Планът за тази заявка е показан на фигура 4.

Фигура 4:План за заявка 4

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

Съвет 3:Не забравяйте да следвате съвети 1 и 2 за първата поява на всяка отделна нужда от поръчка. Последващите случаи на една и съща нужда от подреждане, дори ако не са съседни, се идентифицират и групират заедно с първата.

Съвети 4 и 5

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

Например, да предположим, че искате същия резултат като този, получен от Заявка 2 по отношение на реда на колоните отляво надясно в изхода (ред на колони:други колони, sum2, sum1, sum3), но предпочитате да имате същия план като този, който получихте за заявка 3 (ред на колони:други колони, sum1, sum3, sum2), който получи два вида вместо четири.

Това е напълно изпълнимо, ако сте запознати с четвъртия съвет.

Съвет 4:Гореспоменатите препоръки се отнасят за реда на показване на функциите на прозореца в кода, дори ако е в рамките на израз на именувана таблица, като CTE или изглед, и дори ако външната заявка връща колоните в различен ред от този в наименован табличен израз. Ето защо, ако трябва да върнете колони в определен ред в изхода и той е различен от оптималния ред по отношение на минимизиране на сортирането в плана, следвайте съветите по отношение на реда на външния вид в рамките на наименуван табличен израз и върнете колоните във външната заявка в желания изходен ред.

Следната заявка, която ще наричам Запитване 5, илюстрира тази техника:

WITH C AS( SELECT orderid, orderdate, custid, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid ROWS НЕОГРАНИЧЕН ПРЕДШЕСТВЕН) КАТО sum1, SUM(1.0 * orderid) OVER(ORDER BY orderid РЕДОВ ПРЕДВАРИТЕЛЕН НЕОБГРАНИЧЕН) КАТО sum3, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum2 FROM dbo.Orders )SELECT orderid, orderdate, custid, sum2, sum1, sum3FROM CORDER BY custid, orderid; 

Планът за тази заявка е показан на Фигура 5.

Фигура 5:План за заявка 5

Все още получавате само два вида в плана, въпреки факта, че реда на колоните в изхода е:други колони, sum2, sum1, sum3, както в заявка 2.

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

Помислете за следната заявка, която ще наричам Заявка 6:

WITH C AS( SELECT orderid, orderdate, custid, MAX(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВА) КАТО max1, MAX(orderid) НАД (ПОРЕД ОТ поръчан идентификатор НЕОГРАНИЧЕН) КАТО max3 , MAX(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО max2, AVG(orderid) OVER(PARTITION BY custid ORDER BY дата на поръчка, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО avg1.0 AVG. BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО avg3, AVG(orderid) НАД (РАЗДЕЛЯНЕ ПО custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО avg2, SUM(orderid) НАД (РАЗДЕЛЯНЕ BY custid ORDER BY CUSTID ORDER BY CUSTID ПРЕДВАРИТЕЛЕН идентификационен номер 2) SUM ) НАД (ПОРЪЧАНЕ ПО custid ПОРЪЧКА ПО дата на поръчка, идентификатор на поръчка РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВУВАЩ) КАТО sum1, SUM(1.0 * orderid) НАД (ПОРЪЧКА ПО наредени РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО сума3 ОТ dbo.Orders )ИЗБЕРЕТЕ идентификатор на поръчка, sudmdate, sum, sum , sum3, max2, max1, max3, avg2, avg1, avg3FROM COR DER BY custid, orderid;

Тук всички колони за израз на таблица се препращат от външната заявка, така че оптимизацията се извършва въз основа на първото отделно появяване на всяка нужда от подреждане в рамките на израза на таблицата:

  • max1:custid, orderdate, orderid
  • max3:идентификатор на поръчката
  • max2:custid, orderid

Това води до план само с два вида, както е показано на Фигура 6.

Фигура 6:План за заявка 6

Сега променете само външната заявка, като премахнете препратките към max2, max1, max3, avg2, avg1 и avg3, както следва:

WITH C AS( SELECT orderid, orderdate, custid, MAX(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВА) КАТО max1, MAX(orderid) НАД (ПОРЕД ОТ поръчан идентификатор НЕОГРАНИЧЕН) КАТО max3 , MAX(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО max2, AVG(orderid) OVER(PARTITION BY custid ORDER BY дата на поръчка, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО avg1.0 AVG. BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО avg3, AVG(orderid) НАД (РАЗДЕЛЯНЕ ПО custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО avg2, SUM(orderid) НАД (РАЗДЕЛЯНЕ BY custid ORDER BY CUSTID ORDER BY CUSTID ПРЕДВАРИТЕЛЕН идентификационен номер 2) SUM ) НАД (ПОРЪЧАНЕ ПО custid ПОРЪЧКА ПО дата на поръчка, идентификатор на поръчка РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВУВАЩ) КАТО sum1, SUM(1.0 * orderid) НАД (ПОРЪЧКА ПО наредени РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО сума3 ОТ dbo.Orders )ИЗБЕРЕТЕ идентификатор на поръчка, sudmdate, sum, sum , sum3FROM CORDER BY custid, orderid;

Ще наричам тази заявка Заявка 7. Изчисленията на max1, max3, max2, avg1, avg3 и avg2 в табличния израз са ирелевантни за външната заявка, така че са изключени. Останалите изчисления, включващи функции на прозореца в табличния израз, които са от значение за външната заявка, са тези на sum2, sum1 и sum3. За съжаление, те не се появяват в табличния израз в оптимален ред по отношение на минимизиране на сортовете. Както можете да видите в плана за тази заявка, както е показано на фигура 7, има четири вида.

Фигура 7:План за заявка 7

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

Съвет 5:Във вътрешната заявка на израз на именувана таблица, като CTE или изглед, групирайте всички функции на прозореца със същите нужди за подреждане заедно и следвайте съвети 1 и 2 в реда на групите функции.

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

СЪЗДАВАНЕ ИЛИ ПРОМЕНЯНЕ НА ИЗГЛЕЖДАНЕ dbo.MyViewAS SELECT orderid, orderdate, custid, MAX(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВАЩ) КАТО max1, SUM(orderid) OVER(custidte ORDBYERDA) , подредени РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum1, AVG(orderid) НАД(ПОРЪЧАНЕ ПО custid ORDER BY дата на поръчка, идентификатор на поръчката РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВУВАЩ) КАТО avg1, MAX(orderid) НАД (ПОРЕД ПО ПОРЪЧЕН РЕДОВЕ РЕДОВ НЕОГРАНИЧЕН) КАТО ПРЕДВАРИТЕЛНО *3 макс. orderid) НАД(ПОРЪЧКА ПО РЕДОВЕ РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum3, AVG(1.0 * orderid) НАД (ПОРЪЧКА ПО РЕДОВЕ РЕДОВЕ, НЕОГРАНИЧЕНИ ПРЕДШЕСТВУВАЩИ) КАТО avg3, MAX(orderid) НАД (РАЗДЕЛЯНЕ ПО custid ПОРЪЧКА ПО ПОРЪЧКА ПО ПРЕДПРЕДПОРЪЧКА) ROWD2 , AVG(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВУВАЩ) КАТО avg2, SUM(orderid) OVER(PARTITION BY custid ORDER BY подредени РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВУВАЩ) КАТО sum2 ОТ ПРЕДШЕСТВУВАНЕ;
 Сега потърсете изгледа, изисквайки само колоните с резултати в прозорец sum2, sum1 и sum3, в този ред:

ИЗБЕРЕТЕ orderid, orderdate, custid, sum2, sum1, sum3FROM dbo.MyViewORDER BY custid, orderid;

Ще наричам тази заявка Заявка 8. Получавате плана, показан на Фигура 8, само с два вида.

Фигура 8:План за заявка 8

Съвет 6

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

Нека демонстрирам това. Припомнете си по-рано, когато създадохте индекса idx_nc_cid_od_oid, който може да поддържа функции на прозореца, нуждаещи се от данните, подредени по custid, orderdate, orderid, като следния израз:

SUM(orderid) OVER(PARTITION BY custid ORDER BY дата на поръчка, orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ)

Да предположим, че в допълнение към тази функция на прозореца, имате нужда и от следната функция на прозореца в същата заявка:

SUM(orderid) OVER(PARTITION BY custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ)

Тази функция на прозореца ще се възползва от следния индекс:

СЪЗДАЙТЕ УНИКАЛЕН НЕКЛУСТРИРАН ИНДЕКС idx_nc_cid_oid НА dbo.Orders(custid, orderid);

Следната заявка, която ще наричам Заявка 9, извиква и двете функции на прозореца:

SELECT orderid, orderdate, custid, SUM(orderid) OVER(PARTITION BY custid ORDER BY orderdate, orderid ROWS НЕОГРАНИЧЕН ПРЕДШЕСТВУВАЩ) КАТО sum1, SUM(orderid) НАД (PARTITION BY custid ORDER BY orderid КАТО РЕДОВ ПРЕДВАРИТЕЛЕН РЕДОВ ПРЕДВАРИТЕЛЕН FROMDE) dbo.Поръчки;

Планът за тази заявка е показан на Фигура 9.

Фигура 9:План за заявка 9

Получавам следната статистика за времето за тази заявка на моята машина, като резултатите се отхвърлят в SSMS:

Време на процесора =3234 ms, изминало време =3354 ms.

Както беше обяснено по-рано, SQL Server сканира прозоречни изрази по реда на появяване в заявката и представя, че може да поддържа първия с подредено сканиране на индекса idx_nc_cid_od_oid. Но след това добавя оператор за сортиране към плана, за да подреди данните, каквито са необходими на функцията за втория прозорец. Това означава, че планът има N log N мащабиране. Той не обмисля използването на индекса idx_nc_cid_oid за поддръжка на функцията на втория прозорец. Вероятно си мислите, че не може, но се опитайте да мислите малко извън рамката. Не бихте ли могли да изчислите всяка от функциите на прозореца въз основа на съответния й индексен ред и след това да присъедините резултатите? Теоретично можете и в зависимост от размера на данните, наличието на индексиране и други налични ресурси, версията за присъединяване понякога може да се справи по-добре. SQL Server не разглежда този подход, но със сигурност можете да го приложите, като напишете присъединяването сами, така:

С C1 AS( ИЗБЕРЕТЕ идентификатор на поръчка, дата на поръчка, custid, SUM(orderid) НАД (РАЗДЕЛЯНЕ ПО custid ORDER BY дата на поръчка, идентификатор на поръчката РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum1 ОТ dbo.Orders),C2 AS( SELECT orderid, custid, SUM( orderid) НАД (РАЗДЕЛЯНЕ ПО custid ORDER BY orderid РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДИШНИ) КАТО sum2 ОТ dbo.Orders)SELECT C1.orderid, C1.orderdate, C1.custid, C1.sum1, C2.sum2FROM C1 INNER C1 JOIN C2.rid ON C2.orderid;

Ще наричам тази заявка заявка 10. Планът за тази заявка е показан на фигура 10.

Фигура 10:План за заявка 10

Планът използва подредени сканирания на двата индекса без каквото и да е изрично сортиране, изчислява функциите на прозореца и използва хеш присъединяване, за да обедини резултатите. Този план се мащабира линейно в сравнение с предишния, който има N log N мащабиране.

Получавам следната статистика за времето за тази заявка на моята машина (отново с отхвърлени резултати в SSMS):

Време на процесора =1000 мс, изминало време =1100 мс.

За да обобщим, ето нашия шести съвет.

Съвет 6:Когато имате множество функции на прозореца с множество различни нужди за подреждане и сте в състояние да поддържате всички от тях с индекси, опитайте версия за присъединяване и сравнете ефективността й със заявката без присъединяването.

Почистване

Ако сте деактивирали паралелизма, като зададете конфигурационната опция MAXDOP с обхват на базата данни на 1, активирайте отново паралелизма, като го зададете на 0:

ПРОМЕНЯ КОНФИГУРАЦИЯ ЗА ОБХВАТ НА БАЗА ДАННИ MAXDOP =0;

Ако сте използвали недокументираната опция за сесия DBCC OPTIMIZER_WHATIF с опцията CPU, зададена на 1, активирайте отново паралелизма, като я зададете на 0:

DBCC OPTIMIZER_WHATIF(CPUs, 0);

Можете да опитате отново всички примери с активиран паралелизъм, ако желаете.

Използвайте следния код, за да почистите новите индекси, които сте създали:

ИЗПУСКАНЕ ИНДЕКС, АКО СЪЩЕСТВУВА idx_nc_cid_od_oid НА dbo.Orders; ИЗПУСКАНЕ ИНДЕКС, АКО СЪЩЕСТВУВА idx_nc_cid_oid В dbo.Orders;

И следния код за премахване на изгледа:

ОТПУСКАНЕ НА ИЗГЛЕД, АКО СЪЩЕСТВУВА dbo.MyView;

Следвайте съветите за минимизиране на броя на сортовете

Функциите на прозореца трябва да обработват поръчаните входни данни. Индексирането може да помогне за премахване на сортирането в плана, но обикновено само за една отделна нужда от подреждане. Заявките с множество нужди за подреждане обикновено включват някои видове в своите планове. Въпреки това, като следвате определени съвети, можете да сведете до минимум броя на необходимите видове. Ето обобщение на съветите, които споменах в тази статия:

  • Съвет 1: Ако имате индекс за поддръжка на някои от функциите на прозореца в заявката, първо ги посочете.
  • Съвет 2: Ако заявката включва прозоречни функции със същата нужда от подреждане като подреждането на презентацията в заявката, посочете тези функции последни.
  • Съвет 3: Не забравяйте да следвате съвети 1 и 2 за първото появяване на всяка отделна нужда от поръчка. Последващите случаи на една и съща нужда от подреждане, дори ако не са съседни, се идентифицират и групират заедно с първата.
  • Съвет 4: Гореспоменатите препоръки се прилагат към реда на изглед на функциите на прозореца в кода, дори ако е в рамките на израз на именувана таблица, като CTE или изглед, и дори ако външната заявка връща колоните в различен ред от този в израза на именувана таблица. Ето защо, ако трябва да върнете колони в определен ред в изхода и той е различен от оптималния ред по отношение на минимизиране на сортирането в плана, следвайте съветите по отношение на реда на външния вид в рамките на наименуван табличен израз и върнете колоните във външната заявка в желания изходен ред.
  • Съвет 5: Във вътрешната заявка на израз на именувана таблица, като CTE или изглед, групирайте всички функции на прозореца със същите нужди за подреждане заедно и следвайте съвети 1 и 2 в реда на групите функции.
  • Съвет 6: Когато имате множество функции на прозореца с множество различни нужди за подреждане и сте в състояние да поддържате всички от тях с индекси, опитайте версия за присъединяване и сравнете нейната производителност със заявката без присъединяването.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Модел на партийни взаимоотношения. Как да моделирам взаимоотношения

  2. NoSQL:живот без схема

  3. 13 статии в блога за най-добри практики и съвети за проектиране на бази данни

  4. Базиране на модели на бази данни в реалността:Предизвикателството на блогъра

  5. Автоматизирано тестване на настолното приложение:преглед на целесъобразността и рамки