грозен. Така изглеждат несортираните данни. Правим данните лесни за очите, като ги сортираме. И за това е SQL ORDER BY. Използвайте една или повече колони или изрази като основа за сортиране на данни. След това добавете ASC или DESC, за да сортирате възходящо или низходящо.
Синтаксисът на SQL ORDER BY:
<предварителен>код>ПОРЪЧАЙ ПО <подреждане_по_израз> [ASC | DESC]
Изразът ORDER BY може да бъде прост като списък с колони или изрази. Може също да бъде условно, като се използва блок CASE WHEN.
Много е гъвкав.
Можете също да използвате страници чрез OFFSET и FETCH. Посочете броя на редовете, които да пропуснете, и редовете за показване.
Но ето лошите новини.
Добавянето на ORDER BY към вашите заявки може да ги забави. И някои други предупреждения могат да направят ORDER BY „неработещи“. Не можете просто да ги използвате, когато пожелаете, тъй като може да има наказания. И така, какво да правим?
В тази статия ще разгледаме какво трябва и какво не трябва да използвате при използването на ORDER BY. Всеки елемент ще се справи с проблем и ще последва решение.
Готови ли сте?
Направете в SQL ORDER BY
1. Индексирайте SQL ORDER BY колона(и)
Индексите са свързани с бързо търсене. А наличието на такъв в колоните, които използвате в клаузата ORDER BY, може да ускори заявката ви.
Нека започнем да използваме ORDER BY в колона без индекс. Ще използваме AdventureWorks примерна база данни. Преди да изпълните заявката по-долу, деактивирайте IX_SalesOrderDetail_ProductID индекс в SalesOrderDetail маса. След това натиснете Ctrl-M и го стартирайте.
-- Вземете подробности за поръчката по продукт и ги сортирайте по ProductIDUSE AdventureWorksGOSET STATISTICS IO ONGOSELECT ProductID,OrderQty,UnitPrice,LineTotalFROM Sales.SalesOrderDetailORDER BY ProductIDSET STATISTICS IO OFFGO
АНАЛИЗ
Кодът по-горе ще изведе I/O статистическите данни в раздела Съобщения на SQL Server Management Studio. Ще видите плана за изпълнение в друг раздел.
БЕЗ ИНДЕКС
Първо, нека вземем логическите показания от STATISTICS IO. Вижте фигура 1.
Фигура 1 . Логически четене с помощта на ORDER BY на неиндексирана колона. (Форматирано с помощта на statisticsparser.com )
Без индекса, заявката използва 1313 логически четения. И тази Работна маса ? Това означава, че SQL Server е използвал TempDB за да обработите сортирането.
Но какво се случи зад кулисите? Нека разгледаме плана за изпълнение на фигура 2.
Фигура 2 . План за изпълнение на заявка, използваща ORDER BY на неиндексирана колона.
Видяхте ли този оператор на паралелизъм (събиране на потоци)? Това означава, че SQL Server е използвал повече от 1 процесор за обработка на тази заявка. Заявката беше достатъчно тежка, за да изисква повече процесори.
И така, какво ще стане, ако SQL Server използва TempDB и още процесори? Лошо е за обикновена заявка.
С ИНДЕКС
Как ще се справи, ако индексът бъде активиран отново? Нека разберем. Изградете отново индекса IX_SalesOrderDetail_ProductID . След това изпълнете отново заявката по-горе.
Проверете новите логически показания на фигура 3.
Фигура 3 . Нови логически четения след възстановяване на индекса.
Това е много по-добре. Намаляхме броя на логическите четения почти наполовина. Това означава, че индексът го кара да консумира по-малко ресурси. И Работната маса ? Няма го! Няма нужда да използвате TempDB .
А планът за изпълнение? Вижте Фигура 4.
Фигура 4 . Новият план за изпълнение е по-опростен, когато индексът е възстановен.
Виждаш ли? Планът е по-прост. Няма нужда от допълнителни процесори, за да сортирате същите 121 317 реда.
И така, долният ред е:Уверете се, че колоните, които използвате за ORDER BY, са индексирани .
НО АКО ДОБАВЯНЕТО НА ИНДЕКС ВЛИЯНЕ НА ЕФЕКТИВНОСТТА НА ПИСАНЕТО?
Добър въпрос.
Ако това е проблемът, можете да изхвърлите част от изходната таблица във временна таблица или оптимизирана за паметта . След това индексирайте тази таблица. Използвайте същото, ако са включени повече таблици. След това оценете ефективността на заявката на избраната от вас опция. По-бързият вариант ще бъде победител.
2. Ограничете резултатите с WHERE и OFFSET/FETCH
Нека използваме различна заявка. Да кажем, че трябва да покажете информация за продукта със снимки в приложение. Изображенията могат да направят заявките още по-тежки. Така че няма да проверяваме само логическите четения, но и логическите четения.
Ето кода.
ЗАДАДЕТЕ СТАТИСТИКА IO ONGOSELECT a.ProductID,a.Name КАТО ProductName,a.ListPrice,a.Color,b.Name КАТО ProductSubcategory,d.ThumbNailPhoto,d.LargePhotoFROM Production.Product aINNER JOIN Production.ProductSubcategory ON a.ProductSubcategoryID =b.ProductSubcategoryIDINNER JOIN Production.ProductProductPhoto c ON a.ProductID =c.ProductIDINNER JOIN Production.ProductPhoto d ON c.ProductPhotoID =d.ProductPhotoIDWHERE b.ProductPhotoIDWHERE b.ProductPhotoIDWHERE b.ProductPhotoIDWHERE b.ProductCategory, a.ProductCatego. СТАТИСТИКА IO OFFGO
Това ще изведе 97 велосипеда със снимки. Те са много трудни за сърфиране на мобилно устройство.
АНАЛИЗ
ИЗПОЛЗВАНЕ НА МИНИМАЛНО УСЛОВИЯ WHERE БЕЗ ОТМЕСТВАНЕ/ИЗВЪНГВАНЕ
Ето колко логически четения са необходими, за да извлечете 97 продукта със снимки. Вижте Фигура 5.
Фигура 5 . Логическите четения и логическите четения, когато използвате ORDER BY без OFFSET/FETCH и с минимално условие WHERE . (Забележка:statisticsparser.com не показа лобните логически четения. Екранната снимка се редактира въз основа на резултата в SSMS)
Появиха се 667 лобни логически четения поради извличане на изображения в 2 колони. Междувременно за останалите бяха използвани 590 логически четения.
Ето плана за изпълнение на фигура 6, за да можем да го сравним по-късно с по-добрия план.
Фигура 6 . План за изпълнение, използващ ORDER BY без OFFSET/FETCH и с минимално условие WHERE.
Няма какво друго да се каже, докато не видим другия план за изпълнение.
ИЗПОЛЗВАНЕ НА ДОПЪЛНИТЕЛНО УСЛОВИЕ WHERE И ОТМЕСТВАНЕ/ИЗВЛЕЧВАНЕ В ПОРЪЧКА ПО
Сега нека коригираме заявката, за да се уверим, че се връщат минимални данни. Ето какво ще направим:
- Добавете условие към подкатегорията на продукта. В приложението за обаждания можем да си представим да позволим на потребителя да избере и подкатегорията.
- След това премахнете подкатегорията на продукта в списъка SELECT с колони и списъка ORDER BY с колони.
- Накрая добавете OFFSET/FETCH в ORDER BY. Само 10 продукта ще бъдат върнати и показани в приложението за обаждания.
Ето редактирания код.
DECLARE @pageNumber TINYINT =1DECLARE @noOfRows TINYINT =10 -- всяка страница ще показва 10 продукта наведнъж SELECT a.ProductID,a.Name AS ProductName,a.ListPrice,a.Color,d.ThumbNailPhotoFROM Production .Продукт AINNER JOIN Production.ProductSubcategory b ON a.ProductSubcategoryID =b.ProductSubcategoryIDINNER JOIN Production.ProductProductPhoto c ON a.ProductID =c.ProductIDINNER JOIN Production.ProductPhoto d ON ON PRODUCTSubcategoryIDIDN. a.ProductSubcategoryID =2 -- Пътни велосипеди ПОРЪЧАЙТЕ ПО Име на продукта, a.ColorOFFSET (@pageNumber-1)*@noOfRows ИЗВЛЕЧВАНЕ НА РЕДОВЕ СЛЕДВАЩ @noOfRows САМО РЕДОВЕ
Този код ще се подобри допълнително, ако го превърнете в съхранена процедура. Той също така ще има параметри като номер на страница и брой редове. Номерът на страницата показва коя страница разглежда потребителят в момента. Подобрете това допълнително, като направите броя на редовете гъвкав в зависимост от разделителната способност на екрана. Но това е друга история.
Сега, нека разгледаме логическите показания на фигура 7.
Фигура 7 . По-малко логически четения след опростяване на заявката. OFFSET/FETCH също се използва в ORDER BY.
След това сравнете Фигура 7 с Фигура 5. Логическите показания на лоба са изчезнали. В допълнение, логическите показания имат забележимо намаление, тъй като наборът от резултати също беше намален от 97 на 10.
Но какво направи SQL Server зад кулисите? Вижте плана за изпълнение на фигура 8.
Фигура 8 . По-опростен план за изпълнение след опростяване на заявката и добавяне на OFFSET/FETCH в ORDER BY.
След това сравнете фигура 8 с фигура 6. Без да разглеждаме всеки оператор, можем да видим, че този нов план е по-прост от предишния.
Урокът? Опростете заявката си. Използвайте OFFSET/FETCH, когато е възможно.
Не е в SQL ORDER BY
Приключихме с това, което трябва да направим, когато използваме ORDER BY. Този път нека се съсредоточим върху това, което трябва да избягваме.
3. Не използвайте ORDER BY при сортиране по клъстериран индексен ключ
Защото е безполезно.
Нека го покажем с пример.
ЗАДАВАНЕ НА STATISTICS IO ONGO-- Използване на ORDER BY с BusinessEntityID - първичен ключSELECT TOP 100 * FROM Person.PersonORDER BY BusinessEntityID;-- Без изобщо да се използва ORDER BY SELECT TOP 100 * FROM Person.Person;SET STATISTICS IO; OFFGO
След това нека проверим логическите показания на двата оператора SELECT на фигура 9.
Фигура 9 . 2 заявки в таблицата Person показват едни и същи логически показания. Едната е с ORDER BY, другата без.
И двете имат 17 логически показания. Това е логично, защото са върнати същите 100 реда. Но имат ли същия план? Вижте фигура 10.
Фигура 10 . Същият план дали ORDER BY се използва или не при сортиране по клъстерен индексен ключ.
Спазвайте същите оператори и същата цена на заявката.
Но защо? Когато индексирате една или повече колони в клъстериран индекс, таблицата ще бъде физически сортирана чрез клъстерирания индексен ключ. Така че, дори и да не сортирате по този ключ, резултатът пак ще бъде сортиран.
В крайна сметка? Простете си, като не използвате групирания индексен ключ в подобни случаи, като използвате ORDER BY . Спестете енергията си с по-малко натискания на клавиши.
4. Не използвайте ORDER BY , когато колона низ съдържа числа
Ако сортирате по низ колона, съдържаща числа, не очаквайте реда на сортиране като реални типове числа. В противен случай ви очаква голяма изненада.
Ето един пример.
ИЗБЕРЕТЕ NationalIDNumber,JobTitle,HireDateFROM HumanResources.EmployeeORDER BY NationalIDNumber;
Проверете изхода на фигура 11.
Фигура 11 . Последователност на сортиране на колона с низове, съдържаща числа. Числовата стойност не се следва.
На фигура 11 се следва лексикографският ред на сортиране. Така че, за да коригирате това, използвайте CAST към цяло число.
ИЗБЕРЕТЕ NationalIDNumber,JobTitle,HireDateFROM HumanResources.EmployeeORDER BY CAST(NationalIDNumber AS INT)
Вижте Фигура 12 за фиксирания изход.
Фигура 12 . CAST към INT коригира сортирането на колона с низове, съдържаща числа.
Така че, iвместо ORDER BY
5. Не използвайте SELECT INTO #TempTable с ORDER BY
Желаният от вас ред на сортиране няма да бъде гарантиран в целевата временна таблица. Вижте официалната документация .
Нека имаме модифициран код от предишния пример.
ИЗБЕРЕТЕ NationalIDNumber,JobTitle,HireDateINTO #tempFROM HumanResources.Служител ПОРЪЧАЙТЕ ОТ CAST(NationalIDNumber КАТО INT);ИЗБЕРЕТЕ * ОТ #temp;
Единствената разлика от предишния пример е клаузата INTO. Резултатът ще бъде същият като на Фигура 11. Връщаме се в квадрат 1, дори ако CAST колоната е INT.
Трябва да създадете временна таблица, като използвате CREATE TABLE. Но включете допълнителна колона за идентичност и я направете първичен ключ. След това INSERT във временната таблица.
Ето фиксирания код.
СЪЗДАВАНЕ НА ТАБЛИЦА #temp2( id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, NationalIDNumber NVARCHAR(15) NOT NULL, JobTitle NVARCHAR(50) NOT NULL, HireDate DATE NOT NULL)ВЪВЕТЕ ВЪВ #temp2 NationalIDNumber, JobTitle, HireDate)SELECT NationalIDNumber,JobTitle,HireDateFROM HumanResources.EmployeeORDER BY CAST(NationalIDNumber AS INT);SELECT NationalIDNumber,JobTitle,HireDateFROM #Temp2;
И изходът ще бъде същият като на фигура 12. Работи!
Изводи при използването на SQL ORDER BY
Покрихме често срещаните клопки при използването на SQL ORDER BY. Ето обобщение:
Направете :
- Индексирайте колоните ORDER BY,
- Ограничете резултатите с WHERE и OFFSET/FETCH,
Не :
- Не използвайте ORDER BY, когато сортирате по групирания индексен ключ,
- Не използвайте ORDER BY, когато колона с низ съдържа числа. Вместо това първо CAST колоната на низа към INT.
- Не използвайте SELECT INTO #TempTable с ORDER BY. Вместо това създайте първо временната таблица с допълнителна колона за идентичност.
Какви са вашите съвети и трикове при използването на ORDER BY? Уведомете ни в секцията за коментари по-долу. И ако ви харесва тази публикация, моля, споделете я в любимите си социални медийни платформи.