SQL Server съществува повече от 30 години и аз работя със SQL Server почти толкова дълго. Kalen обхваща сканирания в част първа от вътрешните части на SQL Server:проблемни оператори.
Виждал съм много промени през годините (и десетилетия!) и версии на този невероятен продукт. В тези публикации ще споделя с вас как гледам на някои от функциите или аспектите на SQL Server, понякога заедно с малко историческа перспектива.
Настройката на вашите SQL Server заявки е едно от най-добрите неща, които можете да направите за по-добра производителност и оптимизиране на диагностиката на SQL сървър. Но настройката е огромна тема! Познаването как точно да се настрои по най-добрия възможен начин изисква не само задълбочено познаване на вашите данни и вашето работно натоварване, но и познания за това как SQL Server всъщност прави избора си за изпълнение на плана. И така, какво можете да направите, ако не сте експерт по вътрешните части на SQL Server? Едно нещо, което можете да направите, е да разчитате на хора, които са експерти, както и на инструменти, написани от експерти. Инструменти като Quest Spotlight Cloud Tuning Pack могат да ви дадат страхотни предложения, за да започнете по пътя към по-добра производителност на заявките. Разбира се, никой външен инструмент не знае вашите данни и всички подробности за всичките ви работни натоварвания, така че винаги се препоръчва задълбочено тестване на всяко предложение, което решите да приложите.
В тези публикации за проблемни оператори предполагам, че имате някои основни познания за индексните структури на SQL Server. Ето малко информация, която ще бъде полезна:
- Таблица без клъстериран индекс се нарича купчина и няма подреждане. Няма първи и последен ред. Купа е просто куп редове без определен ред.
- Нивото на листа на клъстериран индекс е самата таблица. (Това не е копие на таблицата, а Е таблицата.) Редовете на индекса са логически подредени според колоната, дефинирана като клъстериран индексен ключ.
- Нивото на листа на неклъстериран индекс съдържа индексен ред за всеки ред в таблицата. Редовете съдържат неклъстерираните ключови колони и са логически подредени в реда, в който са посочени ключовете. В допълнение към ключовите колони, неклъстерираните индексни редове съдържат „отметка“, която сочи към посочения ред в таблицата. Отметката може да бъде в една от двете форми:
- Ако таблицата има клъстериран индекс, отметката е ключът за клъстериран индекс. (Ако клъстерираният индексен ключ е част от неклъстерния индексен ключ, той няма да бъде дублиран.)
- Ако таблицата е купчина, отметката е идентификатор на ред или RID, който указва физическото местоположение на реда. Местоположението обикновено се посочва като FileNum:PageNum:RowNum .
Собствените инструменти на SQL Server предоставят множество начини за преглед на плана за изпълнение на заявка, който оптимизаторът е решил да използва за конкретна заявка. С добавянето на Quest Spotlight Tuning Pack можете да получите още повече информация за вашите планове.
Следният код създава копия на две таблици в AdventureWorks база данни (използвам AdventureWorks2016 , но можете да използвате друга версия).
USE AdventureWorks2016;
GO
DROP TABLE IF EXISTS SalesHeader;
GO
SELECT *
INTO SalesHeader
FROM Sales.SalesOrderHeader;
GO
DROP TABLE IF EXISTS SalesDetail;
GO
SELECT * INTO SalesDetail
FROM Sales.SalesOrderDetail;
GO
Сега изпълнете заявка, която свързва двете таблици заедно, след като включите „Включване на действителен план за изпълнение“
SELECT h.SalesOrderID, OrderDate, ProductID, UnitPrice, OrderQty
FROM SalesHeader h JOIN SalesDetail d
ON h.SalesOrderID = d.SalesOrderID
WHERE SalesOrderDetailID < 100;
GO
Quest Spotlight Tuning Pack ще докладва за проблем със заявката, така че можете да кликнете върху „Преглед на анализа“ и да изберете опцията „План за изпълнение“. Трябва да видите следното:
Разбиране на сканирането на таблици
Първо, искам да изляза на крайник и да кажа, че няма оператор на план, който винаги е лош! Защо оптимизаторът би го добавил към вашия план за заявка, ако беше лош? Може да показва, че има място за подобрение във вашите данни или индексни структури, но само по себе си не е лошо.
В примера по-горе, Tuning Pack изглежда акцентира върху сканирането на таблицата, което показва, че те може да са проблематични. Но не винаги е вярно, че сканирането на таблицата е проблематично. Много по-лоша ситуация би била да се използва неклъстерирано търсене на индекс за заявка, която осъществява достъп до всеки ред в таблицата. За тази конкретна заявка бих се съгласил, че сканирането може да не е добро нещо, защото се интересуваме само от няколко реда в SalesDetail таблица (99 от 121 317 реда, или по-малко от една десета от процента.)
Така че можем да разгледаме предложенията в панела Анализ за изграждане на индекси. Предложението за SalesDetail таблица е за изграждане на неклъстериран индекс на SalesOrderID колона (колоната в клаузата JOIN) и ВКЛЮЧВА всяка друга колона в таблицата, която се връща от заявката. Предложението за SalesHeader таблицата е неклъстериран индекс на SalesOrderDetailId колона, която е колоната в клаузата WHERE, и ВКЛЮЧЕТЕ Дата на поръчка колона, която е единствената друга колона, върната от тази таблица.
Ами ако нашата заявка беше малко по-различна? Ами ако бях изпълнил тази заявка, използвайки SELECT * вместо конкретен списък с колони. Ако го опитате и погледнете препоръките, той предлага използването на INNCLUDE за всяка колона в таблицата, различна от колоната с един ключ. Въпреки че такъв индекс може да направи тази конкретна заявка да се изпълнява малко по-бързо, в крайна сметка може да забави други заявки, по-специално вашите UPDATE заявки. Този индекс по същество е просто копие на таблицата, тъй като нивото на листа на индекса ще съдържа всяка една колона в таблицата. Ако видите препоръки като тази, предлагащи индекс, който включва всички колони в таблицата, определено препоръчвам да отстъпите малко назад и да не го създавате сляпо.
Настройката на заявка за диагностиката на вашия SQL сървър включва не само управление на индекси, но и управление на самите заявки. За тази конкретна заявка може би е по-добре да пренапишем заявката, за да НЕ използваме SELECT * за връщане на всеки ред в таблицата. Връщането само на малко подмножество от колоните може да е достатъчно и тогава би бил достатъчен много по-тесен индекс, както в първия пример.
Дали някой от тези индекси всъщност би бил добър индекс за създаване? Като цяло по-тесният индекс ще бъде по-малък и ще бъде по-малко засегнат от актуализации на данните. Индексът на всички колони е като второ копие на таблицата, сортирано в различен ред от самата таблица. Има ситуации, при които разполагането на „второ копие“ на таблицата в различен ред може да бъде полезно, но ще има много режийни разходи за операции за промяна на данни. Единственият начин да знаете със сигурност да изпробвате препоръките за тестова система с представително работно натоварване. Само вие знаете вашите данни и вашите заявки, така че опитайте и вижте!
Разбиране на индексните сканирания
Както споменах по-горе, сканирането на таблицата не винаги е нещо лошо. Но какво да кажем за сканирането на индекс? Тъй като нивото на клъстериран индекс е самата таблица, сканирането на клъстериран индекс е същото като сканирането на таблица! ако сканирането на таблицата е лошо, сканирането на клъстерен индекс е също толкова лошо. Но не винаги е лошо. Отново трябва да го тествате на вашата система.
Препоръките от SQL Server Engine, които Quest Spotlight Tuning Pack показва, никога не предлагат клъстериран индекс. може да предложи неклъстер, който включва всяка колона в таблицата (както беше споменато по-рано), което е просто дубликат на таблицата. Определянето на най-добрата колона или колони за вашия клъстериран индекс е голяма тема само по себе си, така че няма да навлизам в това тук.
Какво е търсене? Операция за търсене в план означава, че SQL Server използва подредените данни в дървото на индекса, за да намери ред, набор от редове или начална и/или точка на спиране в диапазон от редове. Като цяло, използването на неклъстерирано търсене на индекс е напълно разумна операция, ако връщате само много малък процент от редовете от таблица. Но търсенето не е добър избор за заявка, която връща МНОГО редове от таблица. Колко е LOTS? Няма прост отговор, но ако вашата заявка връща повече от няколко процента от редовете, трябва да сте сигурни, че сте тествали внимателно предложенията за индекс. Понякога сканирането на таблица или клъстерното сканиране на индекс е по-добро от търсенето на индекс. (За един такъв пример вижте публикацията ми в блога тук).
Инструменти като Quest Spotlight Tuning Pack може да ви даде страхотни предложения, за да започнете вашето настройване с диагностика на SQL сървър, но колкото повече знаете за това как работят индексите на SQL Server и оптимизатора на SQL Server, толкова по-добре ще можете да оцените тези предложения за вашите заявки и вашите данни и вероятно дори да измислите свои собствени предложения.
В следващите публикации от тази серия ще ви разкажа за други проблемни оператори, които може да се появят в плановете ви за заявка, така че проверете отново скоро!