Выкарыстанне Zabbix для сачэння за базай дадзеных MS SQL Server

Прадмова

Часта ўзнікае запатрабаванне ў рэжыме рэальнага часу паведамляць адміністратару аб праблемах, злучаных з БД (базай дадзеных).

У дадзеным артыкуле будзе апісана, што неабходна наладзіць у Zabbix для сачэння за базай дадзеных MS SQL Server.

Звяртаю ўвагу на тое, што падрабязна як наладжваць прыводзіцца не будзе, аднак формулы і агульныя рэкамендацыі, а таксама падрабязнае апісанне па даданні карыстацкіх элементаў дадзеных праз захоўваемыя працэдуры будуць прыведзены ў дадзеным артыкуле.
Таксама тут будуць разгледжаны толькі асноўныя лічыльнікі прадукцыйнасці.

рашэнне

Спачатку апішу ўсе тыя лічыльнікі прадукцыйнасці (праз элементы дадзеных у Zabbix), якія нам патрэбныя:

  1. Logical Disk
    1. Avg Disc sec/Read
      Паказвае выяўленае ў секундах сярэдні час чытання даных з дыска. Сярэдняе значэнне лічыльніка прадукцыйнасці Avg. Disk sec/Read не павінна перавышаць 10 мілісекунд. Максімальнае значэнне лічыльніка прадукцыйнасці Avg. Disk sec/Read не павінна перавышаць 50 мілісекунд.

      Zabbix: perf_counter[LogicalDisk(_Total)Avg. Disk sec/Read], а таксама важна прасачыць за патрэбнай кружэлкай, напрыклад так: perf_counter[LogicalDisk(C:)Avg. Disk sec/Read]

      Прыклады трыгераў:
      {Назва_вузла:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Read].last()}>0.005, узровень-высокі
      и
      {Назва_вузла:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Read].last()}>0.0025, узровень-сярэдні

    2. Avg Disc sec/Write
      Паказвае выяўлены ў секундах сярэдні час запісу дадзеных на дыск. Сярэдняе значэнне лічыльніка прадукцыйнасці Avg. Disk sec/Write не павінна перавышаць 10 мілісекунд. Максімальнае значэнне лічыльніка прадукцыйнасці Avg. Disk sec/Write не павінна перавышаць 50 мілісекунд.

      Zabbix: perf_counter[LogicalDisk(_Total)Avg. Disk sec/Write], а таксама важна прасачыць за патрэбнай кружэлкай, напрыклад так: perf_counter[LogicalDisk(C:)Avg. Disk sec/Write]

      Прыклады трыгераў:
      {Назва_вузла:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Write].last()}>0.005, узровень-высокі
      и
      {Назва_вузла:perf_counter[LogicalDisk(_Total)Avg. Disk sec/Write].last()}>0.0025, узровень-сярэдні

    3. Avg Disk Queue Length

      Сярэдняя даўжыня чаргі запытаў да дыска. Адлюстроўвае колькасць запытаў да дыска, якія чакаюць апрацоўкі на працягу пэўнага інтэрвалу часу. Нармальным лічыцца чарга не больш за 2 для адзіночнага дыска. Калі ў чарзе больш за два запыты, то, магчыма, дыск перагружаны і не паспявае апрацоўваць паступаючыя запыты. Удакладніць, з якімі менавіта аперацыямі не спраўляецца кружэлка, можна з дапамогай лічыльнікаў Avg. Disk Read Queue Length (чарга запытаў на чытанне) і Avg. Disk Wright Queue Length (чарга запытаў на запіс).
      Значэнне Avg. Disk Queue Length не вымяраецца, а разлічваецца па законе Літла з матэматычнай тэорыі чэргаў. Згодна з гэтым законам, колькасць запытаў, якія чакаюць апрацоўкі, у сярэднім роўная частаце паступлення запытаў, памножанай на час апрацоўкі запыту. Г.зн. у нашым выпадку Avg. Disk Queue Length = (Disk Transfers/sec) * (Avg. Disk sec/Transfer).

      Avg. Disk Queue Length прыводзіцца як адзін з асноўных лічыльнікаў для вызначэння загружанасці дыскавай падсістэмы, аднак для яго адэкватнай адзнакі неабходна сапраўды ўяўляць фізічную структуру сістэмы захоўвання. Да прыкладу, для адзінкавай цвёрдай кружэлкі крытычным лічыцца значэнне больш 2, а калі кружэлка размяшчаецца на RAID-масіве з 4-х кружэлак, то хвалявацца варта пры значэнні больш 4*2=8.

      Zabbix: perf_counter[LogicalDisk(_Total)Avg. Disk Queue Length], а таксама важна прасачыць за патрэбнай кружэлкай, напрыклад так: perf_counter[LogicalDisk(C:)Avg. Disk Queue Length]

  2. памяць
    1. Pages/sec
      Паказвае колькасць старонак, якія SQL Server лічыў з дыска або запісаў на дыск для таго, каб дазволіць звароты да старонак памяці, якія не былі загружаны ў аператыўную памяць у момант абарачэння. Гэтая велічыня з'яўляецца сумай велічынь Pages Input/sec і Pages Output/sec, а таксама ўлічвае старонкавы абмен (падпампоўку/свопінг) сістэмнай кэш-памяці для доступу да файлаў дадзеных прыкладанняў. Акрамя таго, сюды ўключаецца падпампоўка не кэшаваных файлаў, якія непасрэдна адлюстроўваюцца ў памяць. Гэта асноўны лічыльнік, за якім варта сачыць у тым выпадку, калі назіраецца вялікая нагрузка на выкарыстанне памяці і злучаны з гэтым залішні старонкавы абмен. Гэты лічыльнік характарызуе велічыню свопінгу і яго нармальнае (не пікавае) значэнне павінна быць блізка да нуля. Павелічэнне свопінгу кажа аб неабходнасці нарошчвання АЗП ці памяншэнні ліку выкананых на серверы прыкладных праграм.

      Zabbix: perf_counter[MemoryPages/sec] Прыклад трыгера:
      {НАЗВА_ВУЗЛА:perf_counter[MemoryPages/sec].min(5m)}>1000, узровень-інфармацыя

    2. Page Faults/sec

      Гэта значэнне лічыльніка памылак старонкі. Памылка старонкі ўзнікае, калі працэс спасылаецца на старонку віртуальнай памяці, якая не знаходзіцца ў працоўным мностве аператыўнай памяці. Дадзены лічыльнік улічвае як тыя памылкі старонкі, якія патрабуюць звароту да дыска, так і тыя, якія выкліканы знаходжаннем старонкі па-за працоўным мноствам у аператыўнай памяці. Большасць працэсараў могуць апрацоўваць памылкі старонкі другога тыпу без асаблівых затрымак. Аднак апрацоўка памылак старонкі першага тыпу, якая патрабуе доступу да дыска, можа прывесці да значных затрымак.

      Zabbix: perf_counter[MemoryPage Faults/sec] Прыклад трыгера:
      {НАЗВА_ВУЗЛА:perf_counter[MemoryPage Faults/sec].min(5m)}>1000, узровень-інфармацыя

    3. Available Bytes

      Адсочвае колькасць даступнай памяці ў байтах для выканання розных працэсаў. Нізкія паказчыкі азначаюць недахоп памяці. Рашэнне - павялічыць памяць. Гэты лічыльнік у большасці выпадкаў павінен быць увесь час вышэй 5000 кв.
      Ёсць сэнс выстаўляць парог для Available Mbytes уручную з меркаванняў:

      •50% свабоднай памяці даступна = Выдатна
      •25% даступна памяці = Патрабуе ўвагі
      •10% свабодна = Магчымыя праблемы
      •Менш 5% даступна памяці= Крытычна для хуткасці, трэба ўмешвацца.
      Zabbix: perf_counter[MemoryAvailable Bytes]

  3. Processor (Total): % Processor Time
    Гэты лічыльнік паказвае працэнтнае стаўленне часу, якое працэсар быў заняты выкананнем аперацый для не прастойваюць патокаў (non-Idle thread). Гэтую велічыню можна разглядаць як долю часу, які прыходзіцца на выкананне карыснай працы. Кожны працэсар можа быць прызначаны які прастойвае струменю, які спажывае непрадуктыўныя цыклы працэсара, не выкарыстоўваныя іншымі струменямі. Для гэтага лічыльніка характэрны непрацяглыя пікі, якія могуць дасягаць 100 працэнтаў. Аднак, калі назіраюцца працяглыя перыяды, калі ўтылізацыя працэсара вышэй за 80 працэнтаў, то сістэма будзе больш эфектыўнай пры выкарыстанні большай колькасці працэсараў.

    Zabbix: perf_counter[Processor(_Total)% Processor Time], тутака ж можа мець месца па ядрах выводзіць
    Прыклад трыгера:
    {НАЗВА_ВУЗЛА:perf_counter[Processor(_Total)% Processor Time].min(5m)}>80, узровень-інфармацыя

  4. Network Interface (*): % Bytes Total/sec
    Агульная колькасць перададзеных і атрыманых байт у секунду па ўсіх інтэрфейсах. Гэта прапускная здольнасць інтэрфейсу (у байтах). Неабходна параўнаць значэнне гэтага лічыльніка з максімальнай прапускной здольнасцю сеткавай платы. Наогул, гэты лічыльнік павінен паказаць не больш за 50% утылізацыі прапускной здольнасці сеткавага адаптара.
    Zabbix: perf_counter[Network Interface(*)Bytes Sent/sec]
  5. MS SQL Server: Access Methods
    Аб'ект Access Methods (Метады доступу) у SQL Server падае лічыльнікі, якія дапамагаюць сачыць за доступам да лагічных дадзеных у рамках базы дадзеных. Фізічны доступ да старонак базы дадзеных на дыску кантралюецца пры дапамозе лічыльнікаў дыспетчара буфераў. Назіранне за метадамі доступу да дадзеных у базе дадзеных дапамагае вызначыць, ці можна павялічыць прадукцыйнасць запытаў шляхам дадання ці змены індэксаў, даданні ці перасоўванні секцый, даданні файлаў ці груп файлаў, дэфрагментацыі індэксаў ці змены тэксту запытаў. Акрамя таго, пры дапамозе лічыльнікаў аб'екта Access Methods можна сачыць за памерам дадзеных, азначнікаў і вольнай прасторы ў базе дадзеных, кантралюючы аб'ём і фрагментацыю для кожнага асобніка сервера. Празмерная фрагментацыя азначнікаў можа значна зменшыць прадукцыйнасць.

    1. Page Splits/sec
      Колькасць разбіццяў старонак у секунду, выкананых у выніку перапаўнення старонак індэкса. Вялікае значэнне гэтага паказчыка азначае, што пры выкананні аперацый устаўкі і змены дадзеных SQL Server даводзіцца выконваць вялікую колькасць рэсурсаёмістых аперацый па разбіцці старонак і пераносе часткі існуючай старонкі на новае месца. Такіх аперацый па магчымасці трэба пазбягаць. Праблему можна паспрабаваць вырашыць двума спосабамі:
      - стварыць кластарны індэкс для слупкоў з аўтапрырашчэннем. У гэтым выпадку новыя запісы не будуць змяшчацца ўнутр старонак, ужо занятых дадзенымі, а будуць паслядоўна займаць новыя старонкі;
      - Перабудаваць індэксы, павялічыўшы значэнне параметру Fillfactor. Гэты параметр дазваляе зарэзерваваць у старонках азначнікаў вольнае месца, якое будзе выкарыстоўвацца для месцавання новых дадзеных, без неабходнасці вырабляць аперацыі разбіцця старонак.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Access MethodsPage Splits/sec»,30] Прыклад трыгера: {НАЗВА_УЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЭМПЛЯРА:Access MethodsPage Splits/sec»,30].last()}>{НАЗВА_УЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЕМ> ()} /30, узровень-інфармацыя
    2. Full Scans/sec
      Колькасць неабмежаваных аперацый поўнага сканавання за секунду. Да такіх аперацый ставяцца сканаванне асноўнай табліцы і поўнае сканаванне азначніка. Стабільнае павышэнне гэтага паказчыка можа сведчыць аб дэградацыі сістэмы (недахоп патрэбных індэксаў, іх моцная фрагментацыя, невыкарыстанне аптымізатарам існуючых індэксаў, наяўнасць невыкарыстоўваемых індэксаў). Аднак, варта адзначыць, што поўнае сканаванне ў невялікіх табліцах не заўсёды дрэнна, т калі ўдаецца ўсю табліцу размясціць у АЗП, то як раз хутчэй будзе вырабіць поўнае сканаванне. Але ў большасці выпадкаў стабільны рост паказчыка гэтага лічыльніка будзе казаць аб дэградацыі сістэмы. Усё гэта дастасавальна толькі для OLTP-сістэм. У OLAP-сістэмах пастаянныя поўныя сканавання-гэта нармальна.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Access MethodsFull Scans/sec»,30]

  6. MS SQL Server: Buffer Manager
    Аб'ект Buffer Manager (дыспетчара буфераў) падае лічыльнікі, якія дазваляюць назіраць за тым, як SQL Server выкарыстоўвае наступныя рэсурсы:
    - памяць для захоўвання старонак дадзеных;
    - лічыльнікі, службоўцы для маніторынгу фізічнага ўводу-высновы, калі SQL Server счытвае і запісвае старонкі баз дадзеных;
    - пашырэнне буфернага пула для пашырэння буфернага кэша з выкарыстаннем хуткай энерганезалежнай памяці, напрыклад цвёрдацельных назапашвальнікаў (SSD);
    - маніторынг памяці і лічыльнікаў, якія выкарыстоўваюцца SQL Server, дапамагае атрымаць наступныя звесткі;
    - Ці існуюць «вузкія месцы», выкліканыя недахопам фізічнай памяці. Калі часта выкарыстоўваныя дадзеныя не могуць быць захаваны ў кэшы, SQL Server змушаны счытваць іх з дыска;
    - Ці можна павысіць эфектыўнасць выканання запытаў, павялічыўшы аб'ём памяці або вылучыўшы дадатковую памяць для кэшавання дадзеных або захоўвання ўнутраных структур SQL Server;
    - наколькі часта SQL Server счытвае дадзеныя з дыска. У параўнанні з іншымі аперацыямі, такімі як доступ да памяці, фізічны ўвод-вывад выконваецца даўжэй. Памяншэнне аб'ёму ўводу-вываду можа павысіць прадукцыйнасць выканання запытаў.

    1. Buffer Cache hit radio
      Паказвае, наколькі дастаткова SQL Server можа размясціць дадзеныя ў буферы кэша. Чым вышэй гэтае значэнне, тым лепш, т.я. для эфектыўнага звароту SQL сервера да старонак дадзеных, яны павінны знаходзіцца ў буферы кэша, і аперацыі фізічнага ўводу-высновы (I/O) павінны адсутнічаць. Калі назіраецца ўстойлівае зніжэнне сярэдняга значэння гэтага лічыльніка, неабходна разгледзець магчымасць дадання АЗП. Гэты паказчык заўсёды павінен быць вышэй за 90% для OLTP-сістэм і вышэй за 50% для OLAP-сістэм.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Buffer ManagerBuffer cache hit ratio»,30] Прыклады трыгераў: {НАЗВА_КІЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЭМПЛЯРА:Buffer ManagerBuffer cache hit ratio»,30].last()}<70, узровень-высокі
      и
      {НАЗВА_ВУЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Buffer ManagerBuffer cache hit ratio»,30].last()}<80, узровень-сярэдні
    2. Page life expectancy
      Паказвае, як доўга старонка будзе ўвесь час знаходзіцца ў памяці ў цяперашнім стане. Калі значэнне ўвесь час падае, тое гэта азначае, што сістэма марнатравіць буферным пулам. Такім чынам, патэнцыйна праца памяці можа выклікаць праблемы, якія прыводзяць да зніжэння прадукцыйнасці. Варта адзначыць, што не існуе ўніверсальнага паказчыка, ніжэй якога можна адназначна судзіць аб тым, што сістэма марнатравіць буферным пулам (паказчык у 300 секунд састарэлы з MS SQL Server 2012).
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Buffer ManagerPage life expectancy»,30] Прыклад трыгера: {НАЗВА_ВУЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЭМПЛЯРА:Buffer ManagerPage life expectancy»,30].last()}<5, узровень-інфармацыя

  7. MS SQL Server: General Statistics
    Аб'ект General Statistics (Агульная статыстыка) у SQL Server падае лічыльнікі, якія дазваляюць назіраць агульную актыўнасць сервера, напрыклад колькасць адначасовых злучэнняў і колькасць карыстачоў у секунду, якія падлучаюцца ці адключаюцца ад кампутара, дзе запушчаны асобнік SQL Server. Гэтыя паказчыкі карысна выкарыстоўваць у вялікіх сістэмах аператыўнай апрацоўкі транзакцый (OLTP), дзе вялікая колькасць кліентаў увесь час падлучаюцца і адключаюцца ад асобніка SQL Server.

    1. Process blocked
      Колькасць блакіраваных ў дадзены момант працэсаў.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:General StatisticsProcesses blocked»,30] Прыклад трыгера: ({НАЗВА_КІЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:General StatisticsProcesses blocked»,30].min(2m,0)}>=0)
      and ({НАЗВА_КІЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:General StatisticsProcesses blocked»,30].time(0)}>=50000)
      and ({НАЗВА_ВУЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:General StatisticsProcesses blocked»,30].time(0)}<=230000), узровень-інфармацыя (тут ідзе абмежаванне па сігналізацыі з 05:00 да 23:00
    2. Падключэнні карыстальнікаў
      Колькасць карыстачоў, падлучаных у дадзены момант да сервера SQL Server.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:General StatisticsUser Connections»,30]

  8. MS SQL Server: Locks
    Аб'ект Locks (Блакіроўкі) у Microsoft SQL Server падае звесткі аб блакаваннях SQL Server, атрыманых для асобных тыпаў рэсурсаў. Блакіроўкі выдаюцца на такія рэсурсы SQL Server, як прачытаныя ці змененыя транзакцыяй радкі, для прадухілення адначасовага выкарыстання рэсурсаў некалькімі транзакцыямі. Напрыклад, калі выключная (X) блакіроўка атрымана транзакцыяй на радок у табліцы, ніякая іншая транзакцыя не зможа змяніць гэты радок, пакуль блакіроўка не будзе вызвалена. Мінімізацыя выкарыстання блакіровак павялічвае паралелізм, што можа палепшыць агульную прадукцыйнасць. Адначасова можа адсочвацца некалькі асобнікаў аб'екта Locks, кожны з якіх будзе ўяўляць сабой блакіроўку асобнага віду рэсурсаў.

    1. Average Wait Time (ms)
      Сярэдняя працягласць чакання (у мілісекундах) для ўсіх запытаў блакіроўкі, пры якіх спатрэбілася чаканне. Гэты лічыльнік паказвае, колькі ў сярэднім працэсам карыстальнікаў даводзіцца праводзіць у чарзе, каб накласці на рэсурс блакаванне. Максімальна дапушчальнае значэнне гэтага лічыльніка цалкам залежыць ад вашай задачы, нейкае сярэдняе значэнне для ўсіх дадаткаў тут вызначыць складана. Занадта высокае значэнне гэтага лічыльніка можа азначаць праблемы з блакіроўкамі ў вашай базе дадзеных.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Locks(_Total)Average Wait Time (ms)»,30] Прыклад трыгера: {НАЗВА_УЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Locks(_Total)Average Wait Time (ms)»,30].last()}>=500, узровень-інфармацыя
    2. Lock Wait Time (ms)
      Сумарны час чакання блакіровак (у мілісекундах) за апошнюю секунду.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Locks(_Total)Lock Wait Time (ms)»,30]
    3. Lock Waits/sec
      Колькасць выпадкаў за апошнюю секунду, калі патоку даводзілася чакаць у сувязі з запытам блакіроўкі.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Locks(_Total)Lock Waits/sec»,30]
    4. Lock Timeouts/sec
      Колькасць паўтораў, калі не ўдаецца атрымаць блакіроўку шляхам цыклічнага абарачэння. Значэнне параметру канфігуравання SQL Server spin counter вызначае колькасць абарачэнняў струменя (spins), перш чым скончыцца час тайм-аўту і струмень пяройдзе ў неактыўны стан.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Locks(_Total)Lock Timeouts/sec»,30] Прыклад трыгера: {НАЗВА_КІЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЭМПЛЯРА:Locks(_Total)Locks(_Total)Lock Timeouts/sec»,30].last()}>1000, узровень-інфармацыя
    5. Lock Requests/sec
      Колькасць запытаў у секунду ўказанага тыпу блакіроўкі.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Locks(_Total)Lock Requests/sec»,30] Прыклад трыгера: {НАЗВА_КІЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЭМПЛЯРА:Locks(_Total)Lock Requests/sec»,30].last()}>500000, узровень-інфармацыя
    6. Lock Number of Deadlocks/sec
      Колькасць запытаў блакіроўкі ў секунду, якія прыводзяць да ўзаемаблакіроўкі. Наяўнасць узаемаблакіровак сведчыць аб няправільна пабудаваных запытах, якія блакуюць сумесныя рэсурсы.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Number of Deadlocks/sec»,30] Прыклад трыгера: {НАЗВА_КІЗЛА:perf_counter[«MSSQL$НАЗВА_ЭКЗЭМПЛЯРА:Locks(_Total)Number of Deadlocks/sec»,30].last()}>1, узровень-высокі

  9. MS SQL Server: Memory Manager
    Аб'ект Memory Manager (Дыспетчар памяці) у Microsoft SQL Server забяспечвае лічыльнікі для кантролю выкарыстання памяці ўсяго сервера. Кантроль над выкарыстаннем памяці ўсяго сервера для адзнакі дзеянняў карыстача і выкарыстанні рэсурсаў можа дапамагчы ідэнтыфікаваць недахоп прадукцыйнасці. Кантроль над памяццю, які выкарыстоўваецца асобнікам SQL Server, можа дапамагчы вызначыць:
    - Ці існуюць недахопы ў недастатковай фізічнай памяці для захоўвання ў кэшы часта выкарыстоўваюцца дадзеных. Калі памяці недастаткова, SQL Server павінен атрымаць дадзеныя з дыска;
    - Ці можа прадукцыйнасць запыту палепшыцца, калі будзе дададзена памяць ці павялічыцца аб'ём даступнай памяці для кэшавання дадзеных або ўнутраных структур SQL Server.

    1. Memory Grants Outstanding
      Указвае агульны лік працэсаў, якія паспяхова атрымалі памяць працоўнай вобласці. Пры стабільным падзенні паказчыка неабходна павялічыць АЗП.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Memory ManagerMemory Grants Outstanding»,30]
    2. Memory Grants Pending
      Паказвае агульны лік працэсаў, якія чакаюць прадастаўлення памяці працоўнай памяці. Пры стабільным росце паказчыка неабходна павялічыць АЗП.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:Memory ManagerMemory Grants Pending»,30]

  10. MS SQL Server: Statistics
    Аб'ект Statistics (Статыстыка) у Microsoft SQL Server забяспечвае працу лічыльнікаў для назірання кампіляцыі і тыпаў запытаў, якія адпраўляюцца асобніку SQL Server. Назіранне за лікам кампіляцый і паўторных кампіляцый запытаў і лікі пакетаў, атрыманых асобнікам SQL Server, дае ўяўленне пра тое, як хутка SQL Server выконвае запыты карыстачоў і наколькі эфектыўна іх апрацоўвае аптымізатар запытаў.

    1. Batch Requests/sec
      Лік пакетаў каманд Transact-SQL, атрыманых за секунду. На гэтую статыстыку ўплываюць любыя абмежаванні (увод-вывад, колькасць карыстачоў, памер кэша, складанасць запытаў і т. д.). Высокая колькасць запытаў пакетаў сведчыць аб высокай прапускной здольнасці.
      Zabbix: perf_counter[«MSSQL$НАЗВА_ЭКЗЕМПЛЯРА:SQL StatisticsBatch Requests/sec»,30]

Апроч усяго вышэй пералічанага таксама можна наладзіць і іншыя элементы дадзеных (а таксама і стварыць трыгеры па іх з наступным абвесткай).
1) памер вольнага месца на дыску
2) памеры БД-файлаў дадзеных і часопіса лога
і г.д.
Аднак усе гэтыя паказчыкі не паказваюць праблему менавіта запытаў у рэальным часе.
Для гэтага неабходна ствараць свае спецыяльныя лічыльнікі.
З прычыны канфідэнцыйнасці, не буду прыводзіць прыклады такіх лічыльнікаў. Тым больш, што яны настройваюцца ўнікальна для кожнай сістэмы. Але адзначу, што для такіх сістэм як 1С, NAV і CRM спецыялізаваныя лічыльнікі стварыць можна сумесна з адпаведнымі распрацоўшчыкамі.
Прывяду прыклад стварэння абагульненага паказчыка, які паказвае колькі запытаў выконваецца і колькі запытаў чакаюць выканання (прыпыненыя або заблакаваныя) на кожны момант часу.
Для гэтага неабходна стварыць захоўваемую працэдуру:
Код

USE [ИМЯ_БАЗЫ_ДАННЫХ]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [nav].[ZabbixGetCountRequestStatus]
	@Status nvarchar(255)
AS
BEGIN
	/*
		возвращает кол-во запросов с заданным статусом
	*/
	SET NOCOUNT ON;

	select count(*) as [Count]
	from sys.dm_exec_requests ER with(readuncommitted)
	where [status]=@Status
END

Далей неабходна зайсці ў тэчку, дзе знаходзіцца Zabbix (zabbixconfuserparams.d) і стварыць 2 файла з пашырэннем ps1 (PowerShell) і напісаць у кожным з іх наступныя коды:
Код для выкананых запытаў

$SQLServer = "НАЗВАНИЕ_ЭКЗЕМПЛЯРА";
$uid = "ЛОГИН"; 
$pwd = "ПАРОЛЬ";
$Status="running";

$connectionString = "Server = $SQLServer; Database=НАЗВАНИЕ_БД; Integrated Security = False; User ID = $uid; Password = $pwd;";

$connection = New-Object System.Data.SqlClient.SqlConnection;
$connection.ConnectionString = $connectionString;

#Создаем запрос непосредственно к MSSQL / Create a request directly to MSSQL
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand;
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure;  
$SqlCmd.CommandText = "nav.ZabbixGetCountRequestStatus";
$SqlCmd.Connection = $Connection;

$paramStatus=$SqlCmd.Parameters.Add("@Status" , [System.Data.SqlDbType]::VarChar);
$paramStatus.Value = $Status;

$connection.Open();
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$SqlAdapter.SelectCommand = $SqlCmd;
$DataSet = New-Object System.Data.DataSet;
$SqlAdapter.Fill($DataSet) > $null;
$connection.Close();

$result = $DataSet.Tables[0].Rows[0]["Count"];

write-host $result;

Код для чакаючых запытаў

$SQLServer = "НАЗВАНИЕ_ЭКЗЕМПЛЯРА";
$uid = "ЛОГИН"; 
$pwd = "ПАРОЛЬ";
$Status="suspended";

$connectionString = "Server = $SQLServer; Database=НАЗВАНИЕ_БД; Integrated Security = False; User ID = $uid; Password = $pwd;";

$connection = New-Object System.Data.SqlClient.SqlConnection;
$connection.ConnectionString = $connectionString;

#Создаем запрос непосредственно к MSSQL / Create a request directly to MSSQL
$SqlCmd = New-Object System.Data.SqlClient.SqlCommand;
$SqlCmd.CommandType = [System.Data.CommandType]::StoredProcedure;  
$SqlCmd.CommandText = "nav.ZabbixGetCountRequestStatus";
$SqlCmd.Connection = $Connection;

$paramStatus=$SqlCmd.Parameters.Add("@Status" , [System.Data.SqlDbType]::VarChar);
$paramStatus.Value = $Status;

$connection.Open();
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter;
$SqlAdapter.SelectCommand = $SqlCmd;
$DataSet = New-Object System.Data.DataSet;
$SqlAdapter.Fill($DataSet) > $null;
$connection.Close();

$result = $DataSet.Tables[0].Rows[0]["Count"];

write-host $result;

Зараз неабходна стварыць файл з карыстацкімі параметрамі і пашырэннем .conf (ці дадаць радкі ў існуючы такі карыстацкі файл, калі ён быў створаны раней) і ўставіць наступныя радкі:
UserParameter=НАЗВА_ПАРАМЕТРА_КІЛЬКАСЦЬ_ВЫКАНАЛЬНЫХ_ЗАПРАТАЎ,powershell -NoProfile -ExecutionPolicy Bypass -File ПОЎНЫ_ШЛЯХzabbixconfuserparams.dНАЗВА_ФАЙЛА_ДЛЯ_ВЫКАННЯМ.
UserParameter=НАЗВА_ПАРАМЕТРА_КІЛЬКАСЦЬ_ЧАКАЮЧЫХ_ЗАПРАТАЎ,powershell -NoProfile -ExecutionPolicy Bypass -File ПОЎНЫ_ШЛЯХzabbixconfuserparams.dНАЗВА_ФАЙЛА_ДЛЯ_ЧЫКУЮЧЫХ.
Пасля гэтага захоўваем файл .conf і перазапускаем агент Zabbix.
Пасля гэтага дадаем у Zabbix новых два элемента (у дадзеным выпадку назвы і ключ супадаюць):
НАЗВА_ПАРАМЕТРА_КІЛЬКАСЦЬ_ВЫКАНАЛЬНЫХ_ЗАПРАТАЎ
НАЗВА_ПАРАМЕТРА_КОЛЬКАСЦЬ_ЧЫНАЮЧЫХ_ЗАПРАТАЎ
Цяпер можна ствараць графікі і трыгеры на створаныя прыстасаваныя элементы дадзеных.

Калі колькасць чакаючых запытаў рэзка ўзрастае, то наступным запытам можна вывесці ўсе выкананыя і якія чакаюць запыты ў дадзены момант часу з дэталізацыяй ад куды і пад якім лагінам выконваецца запыт, тэкст і план запыту, а таксама іншыя дэталі:
Код

/*Активные, готовые к выполнению и ожидающие запросы, а также те, что явно блокируют другие сеансы*/
with tbl0 as (
select ES.[session_id]
,ER.[blocking_session_id]
,ER.[request_id]
,ER.[start_time]
,ER.[status]
,ES.[status] as [status_session]
,ER.[command]
,ER.[percent_complete]
,DB_Name(coalesce(ER.[database_id], ES.[database_id])) as [DBName]
,(select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle])) as [TSQL]
,(select top(1) [objectid] from sys.dm_exec_sql_text(ER.[sql_handle])) as [objectid]
,(select top(1) [query_plan] from sys.dm_exec_query_plan(ER.[plan_handle])) as [QueryPlan]
,ER.[wait_type]
,ES.[login_time]
,ES.[host_name]
,ES.[program_name]
,ER.[wait_time]
,ER.[last_wait_type]
,ER.[wait_resource]
,ER.[open_transaction_count]
,ER.[open_resultset_count]
,ER.[transaction_id]
,ER.[context_info]
,ER.[estimated_completion_time]
,ER.[cpu_time]
,ER.[total_elapsed_time]
,ER.[scheduler_id]
,ER.[task_address]
,ER.[reads]
,ER.[writes]
,ER.[logical_reads]
,ER.[text_size]
,ER.[language]
,ER.[date_format]
,ER.[date_first]
,ER.[quoted_identifier]
,ER.[arithabort]
,ER.[ansi_null_dflt_on]
,ER.[ansi_defaults]
,ER.[ansi_warnings]
,ER.[ansi_padding]
,ER.[ansi_nulls]
,ER.[concat_null_yields_null]
,ER.[transaction_isolation_level]
,ER.[lock_timeout]
,ER.[deadlock_priority]
,ER.[row_count]
,ER.[prev_error]
,ER.[nest_level]
,ER.[granted_query_memory]
,ER.[executing_managed_code]
,ER.[group_id]
,ER.[query_hash]
,ER.[query_plan_hash]
,EC.[most_recent_session_id]
,EC.[connect_time]
,EC.[net_transport]
,EC.[protocol_type]
,EC.[protocol_version]
,EC.[endpoint_id]
,EC.[encrypt_option]
,EC.[auth_scheme]
,EC.[node_affinity]
,EC.[num_reads]
,EC.[num_writes]
,EC.[last_read]
,EC.[last_write]
,EC.[net_packet_size]
,EC.[client_net_address]
,EC.[client_tcp_port]
,EC.[local_net_address]
,EC.[local_tcp_port]
,EC.[parent_connection_id]
,EC.[most_recent_sql_handle]
,ES.[host_process_id]
,ES.[client_version]
,ES.[client_interface_name]
,ES.[security_id]
,ES.[login_name]
,ES.[nt_domain]
,ES.[nt_user_name]
,ES.[memory_usage]
,ES.[total_scheduled_time]
,ES.[last_request_start_time]
,ES.[last_request_end_time]
,ES.[is_user_process]
,ES.[original_security_id]
,ES.[original_login_name]
,ES.[last_successful_logon]
,ES.[last_unsuccessful_logon]
,ES.[unsuccessful_logons]
,ES.[authenticating_database_id]
,ER.[sql_handle]
,ER.[statement_start_offset]
,ER.[statement_end_offset]
,ER.[plan_handle]
,ER.[dop]
,coalesce(ER.[database_id], ES.[database_id]) as [database_id]
,ER.[user_id]
,ER.[connection_id]
from sys.dm_exec_requests ER with(readuncommitted)
right join sys.dm_exec_sessions ES with(readuncommitted)
on ES.session_id = ER.session_id 
left join sys.dm_exec_connections EC  with(readuncommitted)
on EC.session_id = ES.session_id
)
, tbl as (
select [session_id]
,[blocking_session_id]
,[request_id]
,[start_time]
,[status]
,[status_session]
,[command]
,[percent_complete]
,[DBName]
,OBJECT_name([objectid], [database_id]) as [object]
,[TSQL]
,[QueryPlan]
,[wait_type]
,[login_time]
,[host_name]
,[program_name]
,[wait_time]
,[last_wait_type]
,[wait_resource]
,[open_transaction_count]
,[open_resultset_count]
,[transaction_id]
,[context_info]
,[estimated_completion_time]
,[cpu_time]
,[total_elapsed_time]
,[scheduler_id]
,[task_address]
,[reads]
,[writes]
,[logical_reads]
,[text_size]
,[language]
,[date_format]
,[date_first]
,[quoted_identifier]
,[arithabort]
,[ansi_null_dflt_on]
,[ansi_defaults]
,[ansi_warnings]
,[ansi_padding]
,[ansi_nulls]
,[concat_null_yields_null]
,[transaction_isolation_level]
,[lock_timeout]
,[deadlock_priority]
,[row_count]
,[prev_error]
,[nest_level]
,[granted_query_memory]
,[executing_managed_code]
,[group_id]
,[query_hash]
,[query_plan_hash]
,[most_recent_session_id]
,[connect_time]
,[net_transport]
,[protocol_type]
,[protocol_version]
,[endpoint_id]
,[encrypt_option]
,[auth_scheme]
,[node_affinity]
,[num_reads]
,[num_writes]
,[last_read]
,[last_write]
,[net_packet_size]
,[client_net_address]
,[client_tcp_port]
,[local_net_address]
,[local_tcp_port]
,[parent_connection_id]
,[most_recent_sql_handle]
,[host_process_id]
,[client_version]
,[client_interface_name]
,[security_id]
,[login_name]
,[nt_domain]
,[nt_user_name]
,[memory_usage]
,[total_scheduled_time]
,[last_request_start_time]
,[last_request_end_time]
,[is_user_process]
,[original_security_id]
,[original_login_name]
,[last_successful_logon]
,[last_unsuccessful_logon]
,[unsuccessful_logons]
,[authenticating_database_id]
,[sql_handle]
,[statement_start_offset]
,[statement_end_offset]
,[plan_handle]
,[dop]
,[database_id]
,[user_id]
,[connection_id]
from tbl0
where [status] in ('suspended', 'running', 'runnable')
)
, tbl_group as (
select [blocking_session_id]
from tbl
where [blocking_session_id]<>0
group by [blocking_session_id]
)
, tbl_res_rec as (
select [session_id]
,[blocking_session_id]
,[request_id]
,[start_time]
,[status]
,[status_session]
,[command]
,[percent_complete]
,[DBName]
,[object]
,[TSQL]
,[QueryPlan]
,[wait_type]
,[login_time]
,[host_name]
,[program_name]
,[wait_time]
,[last_wait_type]
,[wait_resource]
,[open_transaction_count]
,[open_resultset_count]
,[transaction_id]
,[context_info]
,[estimated_completion_time]
,[cpu_time]
,[total_elapsed_time]
,[scheduler_id]
,[task_address]
,[reads]
,[writes]
,[logical_reads]
,[text_size]
,[language]
,[date_format]
,[date_first]
,[quoted_identifier]
,[arithabort]
,[ansi_null_dflt_on]
,[ansi_defaults]
,[ansi_warnings]
,[ansi_padding]
,[ansi_nulls]
,[concat_null_yields_null]
,[transaction_isolation_level]
,[lock_timeout]
,[deadlock_priority]
,[row_count]
,[prev_error]
,[nest_level]
,[granted_query_memory]
,[executing_managed_code]
,[group_id]
,[query_hash]
,[query_plan_hash]
,[most_recent_session_id]
,[connect_time]
,[net_transport]
,[protocol_type]
,[protocol_version]
,[endpoint_id]
,[encrypt_option]
,[auth_scheme]
,[node_affinity]
,[num_reads]
,[num_writes]
,[last_read]
,[last_write]
,[net_packet_size]
,[client_net_address]
,[client_tcp_port]
,[local_net_address]
,[local_tcp_port]
,[parent_connection_id]
,[most_recent_sql_handle]
,[host_process_id]
,[client_version]
,[client_interface_name]
,[security_id]
,[login_name]
,[nt_domain]
,[nt_user_name]
,[memory_usage]
,[total_scheduled_time]
,[last_request_start_time]
,[last_request_end_time]
,[is_user_process]
,[original_security_id]
,[original_login_name]
,[last_successful_logon]
,[last_unsuccessful_logon]
,[unsuccessful_logons]
,[authenticating_database_id]
,[sql_handle]
,[statement_start_offset]
,[statement_end_offset]
,[plan_handle]
,[dop]
,[database_id]
,[user_id]
,[connection_id]
, 0 as [is_blocking_other_session]
from tbl
union all
select tbl0.[session_id]
,tbl0.[blocking_session_id]
,tbl0.[request_id]
,tbl0.[start_time]
,tbl0.[status]
,tbl0.[status_session]
,tbl0.[command]
,tbl0.[percent_complete]
,tbl0.[DBName]
,OBJECT_name(tbl0.[objectid], tbl0.[database_id]) as [object]
,tbl0.[TSQL]
,tbl0.[QueryPlan]
,tbl0.[wait_type]
,tbl0.[login_time]
,tbl0.[host_name]
,tbl0.[program_name]
,tbl0.[wait_time]
,tbl0.[last_wait_type]
,tbl0.[wait_resource]
,tbl0.[open_transaction_count]
,tbl0.[open_resultset_count]
,tbl0.[transaction_id]
,tbl0.[context_info]
,tbl0.[estimated_completion_time]
,tbl0.[cpu_time]
,tbl0.[total_elapsed_time]
,tbl0.[scheduler_id]
,tbl0.[task_address]
,tbl0.[reads]
,tbl0.[writes]
,tbl0.[logical_reads]
,tbl0.[text_size]
,tbl0.[language]
,tbl0.[date_format]
,tbl0.[date_first]
,tbl0.[quoted_identifier]
,tbl0.[arithabort]
,tbl0.[ansi_null_dflt_on]
,tbl0.[ansi_defaults]
,tbl0.[ansi_warnings]
,tbl0.[ansi_padding]
,tbl0.[ansi_nulls]
,tbl0.[concat_null_yields_null]
,tbl0.[transaction_isolation_level]
,tbl0.[lock_timeout]
,tbl0.[deadlock_priority]
,tbl0.[row_count]
,tbl0.[prev_error]
,tbl0.[nest_level]
,tbl0.[granted_query_memory]
,tbl0.[executing_managed_code]
,tbl0.[group_id]
,tbl0.[query_hash]
,tbl0.[query_plan_hash]
,tbl0.[most_recent_session_id]
,tbl0.[connect_time]
,tbl0.[net_transport]
,tbl0.[protocol_type]
,tbl0.[protocol_version]
,tbl0.[endpoint_id]
,tbl0.[encrypt_option]
,tbl0.[auth_scheme]
,tbl0.[node_affinity]
,tbl0.[num_reads]
,tbl0.[num_writes]
,tbl0.[last_read]
,tbl0.[last_write]
,tbl0.[net_packet_size]
,tbl0.[client_net_address]
,tbl0.[client_tcp_port]
,tbl0.[local_net_address]
,tbl0.[local_tcp_port]
,tbl0.[parent_connection_id]
,tbl0.[most_recent_sql_handle]
,tbl0.[host_process_id]
,tbl0.[client_version]
,tbl0.[client_interface_name]
,tbl0.[security_id]
,tbl0.[login_name]
,tbl0.[nt_domain]
,tbl0.[nt_user_name]
,tbl0.[memory_usage]
,tbl0.[total_scheduled_time]
,tbl0.[last_request_start_time]
,tbl0.[last_request_end_time]
,tbl0.[is_user_process]
,tbl0.[original_security_id]
,tbl0.[original_login_name]
,tbl0.[last_successful_logon]
,tbl0.[last_unsuccessful_logon]
,tbl0.[unsuccessful_logons]
,tbl0.[authenticating_database_id]
,tbl0.[sql_handle]
,tbl0.[statement_start_offset]
,tbl0.[statement_end_offset]
,tbl0.[plan_handle]
,tbl0.[dop]
,tbl0.[database_id]
,tbl0.[user_id]
,tbl0.[connection_id]
, 1 as [is_blocking_other_session]
from tbl_group as tg
inner join tbl0 on tg.blocking_session_id=tbl0.session_id
)
,tbl_res_rec_g as (
select [plan_handle],
[sql_handle],
cast([start_time] as date) as [start_time]
from tbl_res_rec
group by [plan_handle],
[sql_handle],
cast([start_time] as date)
)
,tbl_rec_stat_g as (
select qs.[plan_handle]
,qs.[sql_handle]
--,cast(qs.[last_execution_time] as date)	as [last_execution_time]
,min(qs.[creation_time])					as [creation_time]
,max(qs.[execution_count])				as [execution_count]
,max(qs.[total_worker_time])				as [total_worker_time]
,min(qs.[last_worker_time])				as [min_last_worker_time]
,max(qs.[last_worker_time])				as [max_last_worker_time]
,min(qs.[min_worker_time])				as [min_worker_time]
,max(qs.[max_worker_time])				as [max_worker_time]
,max(qs.[total_physical_reads])			as [total_physical_reads]
,min(qs.[last_physical_reads])			as [min_last_physical_reads]
,max(qs.[last_physical_reads])			as [max_last_physical_reads]
,min(qs.[min_physical_reads])				as [min_physical_reads]
,max(qs.[max_physical_reads])				as [max_physical_reads]
,max(qs.[total_logical_writes])			as [total_logical_writes]
,min(qs.[last_logical_writes])			as [min_last_logical_writes]
,max(qs.[last_logical_writes])			as [max_last_logical_writes]
,min(qs.[min_logical_writes])				as [min_logical_writes]
,max(qs.[max_logical_writes])				as [max_logical_writes]
,max(qs.[total_logical_reads])			as [total_logical_reads]
,min(qs.[last_logical_reads])				as [min_last_logical_reads]
,max(qs.[last_logical_reads])				as [max_last_logical_reads]
,min(qs.[min_logical_reads])				as [min_logical_reads]
,max(qs.[max_logical_reads])				as [max_logical_reads]
,max(qs.[total_clr_time])					as [total_clr_time]
,min(qs.[last_clr_time])					as [min_last_clr_time]
,max(qs.[last_clr_time])					as [max_last_clr_time]
,min(qs.[min_clr_time])					as [min_clr_time]
,max(qs.[max_clr_time])					as [max_clr_time]
,max(qs.[total_elapsed_time])				as [total_elapsed_time]
,min(qs.[last_elapsed_time])				as [min_last_elapsed_time]
,max(qs.[last_elapsed_time])				as [max_last_elapsed_time]
,min(qs.[min_elapsed_time])				as [min_elapsed_time]
,max(qs.[max_elapsed_time])				as [max_elapsed_time]
,max(qs.[total_rows])						as [total_rows]
,min(qs.[last_rows])						as [min_last_rows]
,max(qs.[last_rows])						as [max_last_rows]
,min(qs.[min_rows])						as [min_rows]
,max(qs.[max_rows])						as [max_rows]
,max(qs.[total_dop])						as [total_dop]
,min(qs.[last_dop])						as [min_last_dop]
,max(qs.[last_dop])						as [max_last_dop]
,min(qs.[min_dop])						as [min_dop]
,max(qs.[max_dop])						as [max_dop]
,max(qs.[total_grant_kb])					as [total_grant_kb]
,min(qs.[last_grant_kb])					as [min_last_grant_kb]
,max(qs.[last_grant_kb])					as [max_last_grant_kb]
,min(qs.[min_grant_kb])					as [min_grant_kb]
,max(qs.[max_grant_kb])					as [max_grant_kb]
,max(qs.[total_used_grant_kb])			as [total_used_grant_kb]
,min(qs.[last_used_grant_kb])				as [min_last_used_grant_kb]
,max(qs.[last_used_grant_kb])				as [max_last_used_grant_kb]
,min(qs.[min_used_grant_kb])				as [min_used_grant_kb]
,max(qs.[max_used_grant_kb])				as [max_used_grant_kb]
,max(qs.[total_ideal_grant_kb])			as [total_ideal_grant_kb]
,min(qs.[last_ideal_grant_kb])			as [min_last_ideal_grant_kb]
,max(qs.[last_ideal_grant_kb])			as [max_last_ideal_grant_kb]
,min(qs.[min_ideal_grant_kb])				as [min_ideal_grant_kb]
,max(qs.[max_ideal_grant_kb])				as [max_ideal_grant_kb]
,max(qs.[total_reserved_threads])			as [total_reserved_threads]
,min(qs.[last_reserved_threads])			as [min_last_reserved_threads]
,max(qs.[last_reserved_threads])			as [max_last_reserved_threads]
,min(qs.[min_reserved_threads])			as [min_reserved_threads]
,max(qs.[max_reserved_threads])			as [max_reserved_threads]
,max(qs.[total_used_threads])				as [total_used_threads]
,min(qs.[last_used_threads])				as [min_last_used_threads]
,max(qs.[last_used_threads])				as [max_last_used_threads]
,min(qs.[min_used_threads])				as [min_used_threads]
,max(qs.[max_used_threads])				as [max_used_threads]
from tbl_res_rec_g as t
inner join sys.dm_exec_query_stats as qs with(readuncommitted) on t.[plan_handle]=qs.[plan_handle] 
and t.[sql_handle]=qs.[sql_handle] 
and t.[start_time]=cast(qs.[last_execution_time] as date)
group by qs.[plan_handle]
,qs.[sql_handle]
--,qs.[last_execution_time]
)
select t.[session_id] --Сессия
,t.[blocking_session_id] --Сессия, которая явно блокирует сессию [session_id]
,t.[request_id] --Идентификатор запроса. Уникален в контексте сеанса
,t.[start_time] --Метка времени поступления запроса
,DateDiff(second, t.[start_time], GetDate()) as [date_diffSec] --Сколько в сек прошло времени от момента поступления запроса
,t.[status] --Состояние запроса
,t.[status_session] --Состояние сессии
,t.[command] --Тип выполняемой в данный момент команды
, COALESCE(
CAST(NULLIF(t.[total_elapsed_time] / 1000, 0) as BIGINT)
,CASE WHEN (t.[status_session] <> 'running' and isnull(t.[status], '')  <> 'running') 
THEN  DATEDIFF(ss,0,getdate() - nullif(t.[last_request_end_time], '1900-01-01T00:00:00.000'))
END
) as [total_time, sec] --Время всей работы запроса в сек
, CAST(NULLIF((CAST(t.[total_elapsed_time] as BIGINT) - CAST(t.[wait_time] AS BIGINT)) / 1000, 0 ) as bigint) as [work_time, sec] --Время работы запроса в сек без учета времени ожиданий
, CASE WHEN (t.[status_session] <> 'running' AND ISNULL(t.[status],'') <> 'running') 
THEN  DATEDIFF(ss,0,getdate() - nullif(t.[last_request_end_time], '1900-01-01T00:00:00.000'))
END as [sleep_time, sec] --Время сна в сек
, NULLIF( CAST((t.[logical_reads] + t.[writes]) * 8 / 1024 as numeric(38,2)), 0) as [IO, MB] --операций чтения и записи в МБ
, CASE  t.transaction_isolation_level
WHEN 0 THEN 'Unspecified'
WHEN 1 THEN 'ReadUncommited'
WHEN 2 THEN 'ReadCommited'
WHEN 3 THEN 'Repetable'
WHEN 4 THEN 'Serializable'
WHEN 5 THEN 'Snapshot'
END as [transaction_isolation_level_desc] --уровень изоляции транзакции (расшифровка)
,t.[percent_complete] --Процент завершения работы для следующих команд
,t.[DBName] --БД
,t.[object] --Объект
, SUBSTRING(
t.[TSQL]
, t.[statement_start_offset]/2+1
,	(
CASE WHEN ((t.[statement_start_offset]<0) OR (t.[statement_end_offset]<0))
THEN DATALENGTH (t.[TSQL])
ELSE t.[statement_end_offset]
END
- t.[statement_start_offset]
)/2 +1
) as [CURRENT_REQUEST] --Текущий выполняемый запрос в пакете
,t.[TSQL] --Запрос всего пакета
,t.[QueryPlan] --План всего пакета
,t.[wait_type] --Если запрос в настоящий момент блокирован, в столбце содержится тип ожидания (sys.dm_os_wait_stats)
,t.[login_time] --Время подключения сеанса
,t.[host_name] --Имя клиентской рабочей станции, указанное в сеансе. Для внутреннего сеанса это значение равно NULL
,t.[program_name] --Имя клиентской программы, которая инициировала сеанс. Для внутреннего сеанса это значение равно NULL
,cast(t.[wait_time]/1000 as decimal(18,3)) as [wait_timeSec] --Если запрос в настоящий момент блокирован, в столбце содержится продолжительность текущего ожидания (в секундах)
,t.[wait_time] --Если запрос в настоящий момент блокирован, в столбце содержится продолжительность текущего ожидания (в миллисекундах)
,t.[last_wait_type] --Если запрос был блокирован ранее, в столбце содержится тип последнего ожидания
,t.[wait_resource] --Если запрос в настоящий момент блокирован, в столбце указан ресурс, освобождения которого ожидает запрос
,t.[open_transaction_count] --Число транзакций, открытых для данного запроса
,t.[open_resultset_count] --Число результирующих наборов, открытых для данного запроса
,t.[transaction_id] --Идентификатор транзакции, в которой выполняется запрос
,t.[context_info] --Значение CONTEXT_INFO сеанса
,cast(t.[estimated_completion_time]/1000 as decimal(18,3)) as [estimated_completion_timeSec] --Только для внутреннего использования. Не допускает значение NULL
,t.[estimated_completion_time] --Только для внутреннего использования. Не допускает значение NULL
,cast(t.[cpu_time]/1000 as decimal(18,3)) as [cpu_timeSec] --Время ЦП (в секундах), затраченное на выполнение запроса
,t.[cpu_time] --Время ЦП (в миллисекундах), затраченное на выполнение запроса
,cast(t.[total_elapsed_time]/1000 as decimal(18,3)) as [total_elapsed_timeSec] --Общее время, истекшее с момента поступления запроса (в секундах)
,t.[total_elapsed_time] --Общее время, истекшее с момента поступления запроса (в миллисекундах)
,t.[scheduler_id] --Идентификатор планировщика, который планирует данный запрос
,t.[task_address] --Адрес блока памяти, выделенного для задачи, связанной с этим запросом
,t.[reads] --Число операций чтения, выполненных данным запросом
,t.[writes] --Число операций записи, выполненных данным запросом
,t.[logical_reads] --Число логических операций чтения, выполненных данным запросом
,t.[text_size] --Установка параметра TEXTSIZE для данного запроса
,t.[language] --Установка языка для данного запроса
,t.[date_format] --Установка параметра DATEFORMAT для данного запроса
,t.[date_first] --Установка параметра DATEFIRST для данного запроса
,t.[quoted_identifier] --1 = Параметр QUOTED_IDENTIFIER для запроса включен (ON). В противном случае — 0
,t.[arithabort] --1 = Параметр ARITHABORT для запроса включен (ON). В противном случае — 0
,t.[ansi_null_dflt_on] --1 = Параметр ANSI_NULL_DFLT_ON для запроса включен (ON). В противном случае — 0
,t.[ansi_defaults] --1 = Параметр ANSI_DEFAULTS для запроса включен (ON). В противном случае — 0
,t.[ansi_warnings] --1 = Параметр ANSI_WARNINGS для запроса включен (ON). В противном случае — 0
,t.[ansi_padding] --1 = Параметр ANSI_PADDING для запроса включен (ON)
,t.[ansi_nulls] --1 = Параметр ANSI_NULLS для запроса включен (ON). В противном случае — 0
,t.[concat_null_yields_null] --1 = Параметр CONCAT_NULL_YIELDS_NULL для запроса включен (ON). В противном случае — 0
,t.[transaction_isolation_level] --Уровень изоляции, с которым создана транзакция для данного запроса
,cast(t.[lock_timeout]/1000 as decimal(18,3)) as [lock_timeoutSec] --Время ожидания блокировки для данного запроса (в секундах)
,t.[lock_timeout] --Время ожидания блокировки для данного запроса (в миллисекундах)
,t.[deadlock_priority] --Значение параметра DEADLOCK_PRIORITY для данного запроса
,t.[row_count] --Число строк, возвращенных клиенту по данному запросу
,t.[prev_error] --Последняя ошибка, происшедшая при выполнении запроса
,t.[nest_level] --Текущий уровень вложенности кода, выполняемого для данного запроса
,t.[granted_query_memory] --Число страниц, выделенных для выполнения поступившего запроса (1 страница-это примерно 8 КБ)
,t.[executing_managed_code] --Указывает, выполняет ли данный запрос в настоящее время код объекта среды CLR (например, процедуры, типа или триггера).
--Этот флаг установлен в течение всего времени, когда объект среды CLR находится в стеке, даже когда из среды вызывается код Transact-SQL
,t.[group_id]	--Идентификатор группы рабочей нагрузки, которой принадлежит этот запрос
,t.[query_hash] --Двоичное хэш-значение рассчитывается для запроса и используется для идентификации запросов с аналогичной логикой.
--Можно использовать хэш запроса для определения использования статистических ресурсов для запросов, которые отличаются только своими литеральными значениями
,t.[query_plan_hash] --Двоичное хэш-значение рассчитывается для плана выполнения запроса и используется для идентификации аналогичных планов выполнения запросов.
--Можно использовать хэш плана запроса для нахождения совокупной стоимости запросов со схожими планами выполнения
,t.[most_recent_session_id] --Представляет собой идентификатор сеанса самого последнего запроса, связанного с данным соединением
,t.[connect_time] --Отметка времени установления соединения
,t.[net_transport] --Содержит описание физического транспортного протокола, используемого данным соединением
,t.[protocol_type] --Указывает тип протокола передачи полезных данных
,t.[protocol_version] --Версия протокола доступа к данным, связанного с данным соединением
,t.[endpoint_id] --Идентификатор, описывающий тип соединения. Этот идентификатор endpoint_id может использоваться для запросов к представлению sys.endpoints
,t.[encrypt_option] --Логическое значение, указывающее, разрешено ли шифрование для данного соединения
,t.[auth_scheme] --Указывает схему проверки подлинности (SQL Server или Windows), используемую с данным соединением
,t.[node_affinity] --Идентифицирует узел памяти, которому соответствует данное соединение
,t.[num_reads] --Число пакетов, принятых посредством данного соединения
,t.[num_writes] --Число пакетов, переданных посредством данного соединения
,t.[last_read] --Отметка времени о последнем полученном пакете данных
,t.[last_write] --Отметка времени о последнем отправленном пакете данных
,t.[net_packet_size] --Размер сетевого пакета, используемый для передачи данных
,t.[client_net_address] --Сетевой адрес удаленного клиента
,t.[client_tcp_port] --Номер порта на клиентском компьютере, который используется при осуществлении соединения
,t.[local_net_address] --IP-адрес сервера, с которым установлено данное соединение. Доступен только для соединений, которые в качестве транспорта данных используют протокол TCP
,t.[local_tcp_port] --TCP-порт сервера, если соединение использует протокол TCP
,t.[parent_connection_id] --Идентифицирует первичное соединение, используемое в сеансе MARS
,t.[most_recent_sql_handle] --Дескриптор последнего запроса SQL, выполненного с помощью данного соединения. Постоянно проводится синхронизация между столбцом most_recent_sql_handle и столбцом most_recent_session_id
,t.[host_process_id] --Идентификатор процесса клиентской программы, которая инициировала сеанс. Для внутреннего сеанса это значение равно NULL
,t.[client_version] --Версия TDS-протокола интерфейса, который используется клиентом для подключения к серверу. Для внутреннего сеанса это значение равно NULL
,t.[client_interface_name] --Имя библиотеки или драйвер, используемый клиентом для обмена данными с сервером. Для внутреннего сеанса это значение равно NULL
,t.[security_id] --Идентификатор безопасности Microsoft Windows, связанный с именем входа
,t.[login_name] --SQL Server Имя входа, под которой выполняется текущий сеанс.
--Чтобы узнать первоначальное имя входа, с помощью которого был создан сеанс, см. параметр original_login_name.
--Может быть SQL Server проверка подлинности имени входа или имени пользователя домена, прошедшего проверку подлинности Windows
,t.[nt_domain] --Домен Windows для клиента, если во время сеанса применяется проверка подлинности Windows или доверительное соединение.
--Для внутренних сеансов и пользователей, не принадлежащих к домену, это значение равно NULL
,t.[nt_user_name] --Имя пользователя Windows для клиента, если во время сеанса используется проверка подлинности Windows или доверительное соединение.
--Для внутренних сеансов и пользователей, не принадлежащих к домену, это значение равно NULL
,t.[memory_usage] --Количество 8-килобайтовых страниц памяти, используемых данным сеансом
,t.[total_scheduled_time] --Общее время, назначенное данному сеансу (включая его вложенные запросы) для исполнения, в миллисекундах
,t.[last_request_start_time] --Время, когда начался последний запрос данного сеанса. Это может быть запрос, выполняющийся в данный момент
,t.[last_request_end_time] --Время завершения последнего запроса в рамках данного сеанса
,t.[is_user_process] --0, если сеанс является системным. В противном случае значение равно 1
,t.[original_security_id] --Microsoft Идентификатор безопасности Windows, связанный с параметром original_login_name
,t.[original_login_name] --SQL Server Имя входа, которую использует клиент создал данный сеанс.
--Это может быть имя входа SQL Server, прошедшее проверку подлинности, имя пользователя домена Windows, 
--прошедшее проверку подлинности, или пользователь автономной базы данных.
--Обратите внимание, что после первоначального соединения для сеанса может быть выполнено много неявных или явных переключений контекста.
--Например если EXECUTE AS используется
,t.[last_successful_logon] --Время последнего успешного входа в систему для имени original_login_name до запуска текущего сеанса
,t.[last_unsuccessful_logon] --Время последнего неуспешного входа в систему для имени original_login_name до запуска текущего сеанса
,t.[unsuccessful_logons] --Число неуспешных попыток входа в систему для имени original_login_name между временем last_successful_logon и временем login_time
,t.[authenticating_database_id] --Идентификатор базы данных, выполняющей проверку подлинности участника.
--Для имен входа это значение будет равно 0.
--Для пользователей автономной базы данных это значение будет содержать идентификатор автономной базы данных
,t.[sql_handle] --Хэш-карта текста SQL-запроса
,t.[statement_start_offset] --Количество символов в выполняемом в настоящий момент пакете или хранимой процедуре, в которой запущена текущая инструкция.
--Может применяться вместе с функциями динамического управления sql_handle, statement_end_offset и sys.dm_exec_sql_text
--для извлечения исполняемой в настоящий момент инструкции по запросу
,t.[statement_end_offset] --Количество символов в выполняемом в настоящий момент пакете или хранимой процедуре, в которой завершилась текущая инструкция.
--Может применяться вместе с функциями динамического управления sql_handle, statement_end_offset и sys.dm_exec_sql_text
--для извлечения исполняемой в настоящий момент инструкции по запросу
,t.[plan_handle] --Хэш-карта плана выполнения SQL
,t.[database_id] --Идентификатор базы данных, к которой выполняется запрос
,t.[user_id] --Идентификатор пользователя, отправившего данный запрос
,t.[connection_id] --Идентификатор соединения, по которому поступил запрос
,t.[is_blocking_other_session] --1-сессия явно блокирует другие сессии, 0-сессия явно не блокирует другие сессии
,coalesce(t.[dop], mg.[dop]) as [dop] --Степень параллелизма запроса
,mg.[request_time] --Дата и время обращения запроса за предоставлением памяти
,mg.[grant_time] --Дата и время, когда запросу была предоставлена память. Возвращает значение NULL, если память еще не была предоставлена
,mg.[requested_memory_kb] --Общий объем запрошенной памяти в килобайтах
,mg.[granted_memory_kb] --Общий объем фактически предоставленной памяти в килобайтах.
--Может быть значение NULL, если память еще не была предоставлена.
--Обычно это значение должно быть одинаковым с requested_memory_kb.
--Для создания индекса сервер может разрешить дополнительное предоставление по требованию памяти,
--объем которой выходит за рамки изначально предоставленной памяти
,mg.[required_memory_kb] --Минимальный объем памяти в килобайтах (КБ), необходимый для выполнения данного запроса.
--Значение requested_memory_kb равно этому объему или больше его
,mg.[used_memory_kb] --Используемый в данный момент объем физической памяти (в килобайтах)
,mg.[max_used_memory_kb] --Максимальный объем используемой до данного момента физической памяти в килобайтах
,mg.[query_cost] --Ожидаемая стоимость запроса
,mg.[timeout_sec] --Время ожидания данного запроса в секундах до отказа от обращения за предоставлением памяти
,mg.[resource_semaphore_id] --Неуникальный идентификатор семафора ресурса, которого ожидает данный запрос
,mg.[queue_id] --Идентификатор ожидающей очереди, в которой данный запрос ожидает предоставления памяти.
--Значение NULL, если память уже предоставлена
,mg.[wait_order] --Последовательный порядок ожидающих запросов в указанной очереди queue_id.
--Это значение может изменяться для заданного запроса, если другие запросы отказываются от предоставления памяти или получают ее.
--Значение NULL, если память уже предоставлена
,mg.[is_next_candidate] --Является следующим кандидатом на предоставление памяти (1 = да, 0 = нет, NULL = память уже предоставлена)
,mg.[wait_time_ms] --Время ожидания в миллисекундах. Значение NULL, если память уже предоставлена
,mg.[pool_id] --Идентификатор пула ресурсов, к которому принадлежит данная группа рабочей нагрузки
,mg.[is_small] --Значение 1 означает, что для данной операции предоставления памяти используется малый семафор ресурса.
--Значение 0 означает использование обычного семафора
,mg.[ideal_memory_kb] --Объем, в килобайтах (КБ), предоставленной памяти, необходимый для размещения всех данных в физической памяти.
--Основывается на оценке количества элементов
,mg.[reserved_worker_count] --Число рабочих процессов, зарезервированной с помощью параллельных запросов, а также число основных рабочих процессов, используемых всеми запросами
,mg.[used_worker_count] --Число рабочих процессов, используемых параллельных запросов
,mg.[max_used_worker_count] --???
,mg.[reserved_node_bitmap] --???
,pl.[bucketid] --Идентификатор сегмента хэша, в который кэшируется запись.
--Значение указывает диапазон от 0 до значения размера хэш-таблицы для типа кэша.
--Для кэшей SQL Plans и Object Plans размер хэш-таблицы может достигать 10007 на 32-разрядных версиях систем и 40009 — на 64-разрядных.
--Для кэша Bound Trees размер хэш-таблицы может достигать 1009 на 32-разрядных версиях систем и 4001 на 64-разрядных.
--Для кэша расширенных хранимых процедур размер хэш-таблицы может достигать 127 на 32-разрядных и 64-разрядных версиях систем
,pl.[refcounts] --Число объектов кэша, ссылающихся на данный объект кэша.
--Значение refcounts для записи должно быть не меньше 1, чтобы размещаться в кэше
,pl.[usecounts] --Количество повторений поиска объекта кэша.
--Остается без увеличения, если параметризованные запросы обнаруживают план в кэше.
--Может быть увеличен несколько раз при использовании инструкции showplan
,pl.[size_in_bytes] --Число байтов, занимаемых объектом кэша
,pl.[memory_object_address] --Адрес памяти кэшированной записи.
--Это значение можно использовать с представлением sys.dm_os_memory_objects,
--чтобы проанализировать распределение памяти кэшированного плана, 
--и с представлением sys.dm_os_memory_cache_entries для определения затрат на кэширование записи
,pl.[cacheobjtype] --Тип объекта в кэше. Значение может быть одним из следующих
,pl.[objtype] --Тип объекта. Значение может быть одним из следующих
,pl.[parent_plan_handle] --Родительский план
--данные из sys.dm_exec_query_stats брались за сутки, в которых была пара (запрос, план)
,qs.[creation_time] --Время компиляции плана
,qs.[execution_count] --Количество выполнений плана с момента последней компиляции
,qs.[total_worker_time] --Общее время ЦП, затраченное на выполнение плана с момента компиляции, в микросекундах (но с точностью до миллисекунды)
,qs.[min_last_worker_time] --Минимальное время ЦП, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[max_last_worker_time] --Максимальное время ЦП, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[min_worker_time] --Минимальное время ЦП, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[max_worker_time] --Максимальное время ЦП, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[total_physical_reads] --Общее количество операций физического считывания при выполнении плана с момента его компиляции.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[min_last_physical_reads] --Минимальное количество операций физического считывания за время последнего выполнения плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[max_last_physical_reads] --Максимальное количество операций физического считывания за время последнего выполнения плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[min_physical_reads] --Минимальное количество операций физического считывания за одно выполнение плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[max_physical_reads] --Максимальное количество операций физического считывания за одно выполнение плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[total_logical_writes] --Общее количество операций логической записи при выполнении плана с момента его компиляции.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[min_last_logical_writes] --Минимальное количество страниц в буферном пуле, загрязненных во время последнего выполнения плана.
--Если страница уже является «грязной» (т. е. измененной), операции записи не учитываются.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[max_last_logical_writes] --Максимальное количество страниц в буферном пуле, загрязненных во время последнего выполнения плана.
--Если страница уже является «грязной» (т. е. измененной), операции записи не учитываются.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[min_logical_writes] --Минимальное количество операций логической записи за одно выполнение плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[max_logical_writes] --Максимальное количество операций логической записи за одно выполнение плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[total_logical_reads] --Общее количество операций логического считывания при выполнении плана с момента его компиляции.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[min_last_logical_reads] --Минимальное количество операций логического считывания за время последнего выполнения плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[max_last_logical_reads] --Максимальное количество операций логического считывания за время последнего выполнения плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[min_logical_reads]	   --Минимальное количество операций логического считывания за одно выполнение плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[max_logical_reads]	--Максимальное количество операций логического считывания за одно выполнение плана.
--Значение всегда равно 0 при запросе оптимизированной для памяти таблицы
,qs.[total_clr_time]	--Время, в микросекундах (но с точностью до миллисекунды),
--внутри Microsoft .NET Framework общеязыковая среда выполнения (CLR) объекты при выполнении плана с момента его компиляции.
--Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
,qs.[min_last_clr_time] --Минимальное время, в микросекундах (но с точностью до миллисекунды),
--затраченное внутри .NET Framework объекты среды CLR во время последнего выполнения плана.
--Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
,qs.[max_last_clr_time] --Максимальное время, в микросекундах (но с точностью до миллисекунды),
--затраченное внутри .NET Framework объекты среды CLR во время последнего выполнения плана.
--Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
,qs.[min_clr_time] --Минимальное время, когда-либо затраченное на выполнение плана внутри объектов .NET Framework среды CLR,
--в микросекундах (но с точностью до миллисекунды).
--Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
,qs.[max_clr_time] --Максимальное время, когда-либо затраченное на выполнение плана внутри среды CLR .NET Framework,
--в микросекундах (но с точностью до миллисекунды).
--Объекты среды CLR могут быть хранимыми процедурами, функциями, триггерами, типами и статистическими выражениями
--,qs.[total_elapsed_time] --Общее время, затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[min_last_elapsed_time] --Минимальное время, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[max_last_elapsed_time] --Максимальное время, затраченное на последнее выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[min_elapsed_time] --Минимальное время, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[max_elapsed_time] --Максимальное время, когда-либо затраченное на выполнение плана, в микросекундах (но с точностью до миллисекунды)
,qs.[total_rows] --Общее число строк, возвращаемых запросом. Не может иметь значение null.
--Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
,qs.[min_last_rows] --Минимальное число строк, возвращенных последним выполнением запроса. Не может иметь значение null.
--Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
,qs.[max_last_rows] --Максимальное число строк, возвращенных последним выполнением запроса. Не может иметь значение null.
--Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
,qs.[min_rows] --Минимальное количество строк, когда-либо возвращенных по запросу во время выполнения один
--Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
,qs.[max_rows] --Максимальное число строк, когда-либо возвращенных по запросу во время выполнения один
--Значение всегда равно 0, если скомпилированная в собственном коде хранимая процедура запрашивает оптимизированную для памяти таблицу
,qs.[total_dop] --Общую сумму по степени параллелизма плана используется с момента его компиляции.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_last_dop] --Минимальная степень параллелизма, если время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_last_dop] --Максимальная степень параллелизма, если время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_dop] --Минимальная степень параллелизма этот план когда-либо используется во время одного выполнения.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_dop] --Максимальная степень параллелизма этот план когда-либо используется во время одного выполнения.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[total_grant_kb] --Общий объем зарезервированной памяти в КБ предоставить этот план, полученных с момента его компиляции.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_last_grant_kb] --Минимальный объем зарезервированной памяти предоставляет в КБ, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_last_grant_kb] --Максимальный объем зарезервированной памяти предоставляет в КБ, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_grant_kb] --Минимальный объем зарезервированной памяти в КБ предоставить никогда не получено в ходе одного выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_grant_kb] --Максимальный объем зарезервированной памяти в КБ предоставить никогда не получено в ходе одного выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[total_used_grant_kb] --Общий объем зарезервированной памяти в КБ предоставить этот план, используемый с момента его компиляции.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_last_used_grant_kb] --Минимальная сумма предоставления используемой памяти в КБ, если время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_last_used_grant_kb] --Максимальная сумма предоставления используемой памяти в КБ, если время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_used_grant_kb] --Минимальный объем используемой памяти в КБ предоставить никогда не используется при выполнении одного плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_used_grant_kb] --Максимальный объем используемой памяти в КБ предоставить никогда не используется при выполнении одного плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[total_ideal_grant_kb] --Общий объем идеальный память в КБ, оценка плана с момента его компиляции.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_last_ideal_grant_kb] --Минимальный объем памяти, идеальным предоставляет в КБ, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_last_ideal_grant_kb] --Максимальный объем памяти, идеальным предоставляет в КБ, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_ideal_grant_kb] --Минимальный объем памяти идеальный предоставления в этот план когда-либо оценка во время выполнения один КБ.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_ideal_grant_kb] --Максимальный объем памяти идеальный предоставления в этот план когда-либо оценка во время выполнения один КБ.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[total_reserved_threads] --Общая сумма по зарезервированным параллельного потоков этот план когда-либо использовавшегося с момента его компиляции.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_last_reserved_threads] --Минимальное число зарезервированных параллельных потоков, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_last_reserved_threads] --Максимальное число зарезервированных параллельных потоков, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_reserved_threads] --Минимальное число зарезервированных параллельного потоков, когда-либо использовать при выполнении одного плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_reserved_threads] --Максимальное число зарезервированных параллельного потоков никогда не используется при выполнении одного плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[total_used_threads] --Общая сумма используется параллельных потоков этот план когда-либо использовавшегося с момента его компиляции.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_last_used_threads] --Минимальное число используемых параллельных потоков, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_last_used_threads] --Максимальное число используемых параллельных потоков, когда время последнего выполнения плана.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[min_used_threads] --Минимальное число используемых параллельных потоков, при выполнении одного плана использовали.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
,qs.[max_used_threads] --Максимальное число используемых параллельных потоков, при выполнении одного плана использовали.
--Он всегда будет равно 0 для запроса к таблице, оптимизированной для памяти
from tbl_res_rec as t
left outer join sys.dm_exec_query_memory_grants as mg on t.[plan_handle]=mg.[plan_handle] and t.[sql_handle]=mg.[sql_handle]
left outer join sys.dm_exec_cached_plans as pl on t.[plan_handle]=pl.[plan_handle]
left outer join tbl_rec_stat_g as qs on t.[plan_handle]=qs.[plan_handle] and t.[sql_handle]=qs.[sql_handle] --and qs.[last_execution_time]=cast(t.[start_time] as date);

Таксама нагадаю, што па сабраных статыстыках можна атрымаць самыя цяжкія запыты:
Код

/*
creation_time - Время, когда запрос был скомпилирован. Поскольку при старте сервера кэш пустой, данное время всегда больше либо равно моменту запуска сервиса. Если время, указанное в этом столбце позже, чем предполагаемое (первое использование процедуры), это говорит о том, что запрос по тем или иным причинам был рекомпилирован.
last_execution_time - Момент фактического последнего выполнения запроса.
execution_count - Сколько раз запрос был выполнен с момента компиляции
Количество выполнений позволяет найти ошибки в алгоритмах - часто в наиболее выполняемых запросах оказываются те, которые находятся внутри каких-либо циклов однако могут быть выполнены перед самим циклом один раз. Например, получение каких-либо параметров из базы данных, не меняющихся внутри цикла.
CPU - Суммарное время использования процессора в миллисекундах. Если запрос обрабатывается параллельно, то это время может превысить общее время выполнения запроса, поскольку суммируется время использования запроса каждым ядром. Во время использования процессора включается только фактическая нагрузка на ядра, в нее не входят ожидания каких-либо ресурсов.
Очевидно, что данный показатель позволяет выявлять запросы, наиболее сильно загружающие процессор.
AvgCPUTime - Средняя загрузка процессора на один запрос. 
TotDuration - Общее время выполнения запроса, в миллисекундах.
Данный параметр может быть использован для поиска тех запросов, которые, независимо от причины выполняются "наиболее долго". Если общее время выполнения запроса существенно ниже времени CPU (с поправкой на параллелизм) - это говорит о том, что при выполнения запроса были ожидания каких-либо ресурсов. В большинстве случаев это связано с дисковой активностью или блокировками, но также это может быть сетевой интерфейс или другой ресурс. 
Полный список типов ожиданий можно посмотреть в описании представления sys.dm_os_wait_stats.
AvgDur - Среднее время выполнения запроса в миллисекундах.
Reads - Общее количество чтений.
Это пожалуй лучший агрегатный показатель, позволяющий выявить наиболее нагружающие сервер запросы.
Логическое чтение - это разовое обращение к странице данных, физические чтения не учитываются.
В рамках выполнения одного запроса, могут происходить неоднократные обращения к одной и той же странице.
Чем больше обращений к страницам, тем больше требуется дисковых чтений, памяти и, если речь идет о повторных обращениях, большее время требуется удерживать страницы в памяти.
Writes - Общее количество изменений страниц данных.
Характеризует то, как запрос "нагружает" дисковую систему операциями записи.
Следует помнить, что этот показатель может быть больше 0 не только у тех запросов, которые явно меняют данные, но также и у тех, которые сохраняют промежуточные данные в tempdb.
AggIO - Общее количество логических операций ввода-вывода (суммарно)
Как правило, количество логических чтений на порядки превышает количество операций записи, поэтому этот показатель сам по себе для анализа применим в редких случаях.
AvgIO - Среднее количество логических дисковых операций на одно выполнение запроса.
Значение данного показателя можно анализировать из следующих соображений:
Одна страница данных - это 8192 байта. Можно получить среднее количество байт данных, "обрабатываемых" данным запросом. Если этот объем превышает реальное количество данных, которые обрабатывает запрос (суммарный объем данных в используемых в запросе таблицах), это говорит о том, что был выбран заведомо плохой план выполнения и требуется заняться оптимизацией данного запроса.
Я встречал случай, когда один запрос делал количество обращений, эквивалентных объему в 5Тб, при этом общий объем данных в это БД был 300Гб, а объем данных в таблицах, задействованных в запросе не превышал 10Гб.
В общем можно описать одну причину такого поведения сервера - вместо использования индекса сервер предпочитает сканировать таблицу или наоборот.
Если объем логических чтений в разы превосходит общие объем данных, то это вызвано повторным обращениям к одним и тем же страницам данных. Помимо того, что в одном запросе таблица может быть использована несколько раз, к одним и тем же страницам сервер обращается например в случаях, когда используется индекс и по результатам поиска по нему, найденные некоторые строки данных лежат на одной и той же странице. Конечно, в таком случае предпочтительным могло бы быть сканирование таблицы - в этом случае сервер обращался бы к каждой странице данных только один раз. Однако этому часто мешают... попытки оптимизации запросов, когда разработчик явно указывает, какой индекс или тип соединения должен быть использован.
Обратный случай - вместо использования индекса было выбрано сканирование таблицы. Как правило, это связано с тем, что статистика устарела и требуется её обновление. Однако и в этом случае причиной неудачно выбранного плана вполне могут оказаться подсказки оптимизатору запросов.
query_text - Текст самого запроса
database_name - Имя базы данных, в находится объект, содержащий запрос. NULL для системных процедур
object_name - Имя объекта (процедуры или функции), содержащего запрос.
*/
with s as (
select  creation_time,
last_execution_time,
execution_count,
total_worker_time/1000 as CPU,
convert(money, (total_worker_time))/(execution_count*1000)as [AvgCPUTime],
qs.total_elapsed_time/1000 as TotDuration,
convert(money, (qs.total_elapsed_time))/(execution_count*1000)as [AvgDur],
total_logical_reads as [Reads],
total_logical_writes as [Writes],
total_logical_reads+total_logical_writes as [AggIO],
convert(money, (total_logical_reads+total_logical_writes)/(execution_count + 0.0))as [AvgIO],
[sql_handle],
plan_handle,
statement_start_offset,
statement_end_offset
from sys.dm_exec_query_stats as qs with(readuncommitted)
where convert(money, (qs.total_elapsed_time))/(execution_count*1000)>=100 --выполнялся запрос не менее 100 мс
)
select
s.creation_time,
s.last_execution_time,
s.execution_count,
s.CPU,
s.[AvgCPUTime],
s.TotDuration,
s.[AvgDur],
s.[Reads],
s.[Writes],
s.[AggIO],
s.[AvgIO],
--st.text as query_text,
case 
when sql_handle IS NULL then ' '
else(substring(st.text,(s.statement_start_offset+2)/2,(
case
when s.statement_end_offset =-1 then len(convert(nvarchar(MAX),st.text))*2      
else s.statement_end_offset    
end - s.statement_start_offset)/2  ))
end as query_text,
db_name(st.dbid) as database_name,
object_schema_name(st.objectid, st.dbid)+'.'+object_name(st.objectid, st.dbid) as [object_name],
sp.[query_plan],
s.[sql_handle],
s.plan_handle
from s
cross apply sys.dm_exec_sql_text(s.[sql_handle]) as st
cross apply sys.dm_exec_query_plan(s.[plan_handle]) as sp

Таксама можна і для MySQL напісаць. Для гэтага трэба ўсталяваць mysql-connector-net і затым напісаць прыкладна такі код:
Код для чакаючых запытаў

#Задаем переменные для подключение к MySQL и само подключение
[string]$sMySQLUserName = 'UserName'
[string]$sMySQLPW = 'UserPassword'
[string]$sMySQLDB = 'db'
[string]$sMySQLHost = 'IP-address'
[void][System.Reflection.Assembly]::LoadWithPartialName("MySql.Data");
[string]$sConnectionString = "server="+$sMySQLHost+";port=3306;uid=" + $sMySQLUserName + ";pwd="+"'" + $sMySQLPW +"'"+ ";database="+$sMySQLDB;
#Open a Database connection
$oConnection = New-Object MySql.Data.MySqlClient.MySqlConnection($sConnectionString)
$Error.Clear()
try
{
$oConnection.Open()
}
catch
{
write-warning ("Could not open a connection to Database $sMySQLDB on Host $sMySQLHost. Error: "+$Error[0].ToString())
}
#The first query
# Get an instance of all objects need for a SELECT query. The Command object
$oMYSQLCommand = New-Object MySql.Data.MySqlClient.MySqlCommand;
# DataAdapter Object
$oMYSQLDataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter;
# And the DataSet Object
$oMYSQLDataSet = New-Object System.Data.DataSet;
# Assign the established MySQL connection
$oMYSQLCommand.Connection=$oConnection;
# Define a SELECT query
$oMYSQLCommand.CommandText='query';
$oMYSQLDataAdapter.SelectCommand=$oMYSQLCommand;
# Execute the query
$count=$oMYSQLDataAdapter.Fill($oMYSQLDataSet, "data");
$result = $oMYSQLDataSet.Tables[0].Rows[0]["Count"];
write-host $result;

Вынік

У дадзеным артыкуле быў разгледжаны прыклад лічыльнікаў прадукцыйнасці (элементы дадзеных) у Zabbix. Дадзены падыход дазваляе апавяшчаць адміністратараў аб розных праблемах у рэальным часе або праз нейкі пэўны час. Такім чынам, дадзены падыход дазваляе мінімізаваць у будучыні наступы крытычнай праблемы і прыпынкі працы СКБД і сервера, што ў сваю чаргу абараняе вытворчасць ад прыпынку працоўных працэсаў.
Папярэдні тэкст: Рэгламентныя працы з базай дадзеных інфармацыйнай сістэмы 24×7 у MS SQL Server

Крыніцы:

» Zabbix 3.4
» Лічыльнікі прадукцыйнасці
» Цэнтр прадукцыйнасці для базы дадзеных Azure SQL і SQL Server Database Engine
» Стыль жыцця SQL
» SQLSkills
» TechNet Microsoft
» Аналізуем выкарыстанне памяці
» Аналіз прадукцыйнасці
» Дакументацыя па SQL
» Нататкі аб Windows

Крыніца: habr.com

Дадаць каментар