استخدام Zabbix لمراقبة قاعدة بيانات MS SQL Server

مقدمة

غالبًا ما تكون هناك حاجة لإبلاغ المسؤول بالمشكلات المتعلقة بقاعدة البيانات (قاعدة البيانات) في الوقت الفعلي.

ستصف هذه المقالة ما يجب تهيئته في Zabbix لمراقبة قاعدة بيانات MS SQL Server.

أود أن ألفت انتباهك إلى حقيقة أنه بالتفصيل لن يتم إعطاء كيفية التهيئة ، ومع ذلك ، سيتم تقديم الصيغ والتوصيات العامة ، بالإضافة إلى وصف تفصيلي لإضافة عناصر البيانات المخصصة من خلال الإجراءات المخزنة في هذه المقالة.
أيضًا ، سيتم اعتبار عدادات الأداء الرئيسية فقط هنا.

حل

أولاً ، سأصف كل عدادات الأداء (من خلال العناصر في Zabbix) التي نحتاجها:

  1. القرص المنطقي
    1. متوسط ​​قرص ثانية / قراءة
      يعرض متوسط ​​الوقت بالثواني لقراءة البيانات من القرص. متوسط ​​قيمة عداد متوسط ​​الأداء. يجب ألا يتجاوز القرص ثانية / القراءة 10 مللي ثانية. الحد الأقصى لقيمة عداد متوسط ​​الأداء. يجب ألا يتجاوز القرص ثانية / القراءة 50 مللي ثانية.

      Zabbix: perf_counter [LogicalDisk (_Total) Avg. Disk sec / Read] ، ومن المهم أيضًا تتبع القرص المطلوب ، على سبيل المثال: perf_counter [LogicalDisk (C:) Avg. قرص ثانية / قراءة]

      أمثلة على الزناد:
      {NOTE_NAME: perf_counter [LogicalDisk (_Total) متوسط قرص ثانية / قراءة] .last ()}> 0.005 ، مستوى مرتفع
      и
      {NOTE_NAME: perf_counter [LogicalDisk (_Total) متوسط قرص ثانية / قراءة] .last ()}> 0.0025 ، مستوى متوسط

    2. متوسط ​​قرص ثانية / كتابة
      يعرض متوسط ​​الوقت بالثواني لكتابة البيانات على القرص. متوسط ​​قيمة عداد متوسط ​​الأداء. يجب ألا يتجاوز القرص ثانية / الكتابة 10 مللي ثانية. الحد الأقصى لقيمة عداد متوسط ​​الأداء. يجب ألا يتجاوز القرص ثانية / الكتابة 50 مللي ثانية.

      Zabbix: perf_counter [LogicalDisk (_Total) Avg. Disk sec / Write] ، ومن المهم أيضًا تتبع القرص المطلوب ، على سبيل المثال: perf_counter [LogicalDisk (C:) Avg. قرص ثانية / كتابة]

      أمثلة على الزناد:
      {NOTE_NAME: perf_counter [LogicalDisk (_Total) متوسط Disk sec / Write] .last ()}> 0.005 ، مستوى مرتفع
      и
      {NOTE_NAME: perf_counter [LogicalDisk (_Total) متوسط Disk sec / Write] .last ()}> 0.0025 ، المستوى المتوسط

    3. متوسط ​​طول قائمة انتظار القرص

      متوسط ​​طول قائمة انتظار الطلبات على القرص. يعرض عدد طلبات القرص المعلقة خلال فترة زمنية محددة. لا تزيد قائمة الانتظار العادية عن 2 لقرص واحد. إذا كان هناك أكثر من طلبين في قائمة الانتظار ، فمن المحتمل أن يكون القرص محملاً بشكل زائد وليس لديه الوقت لمعالجة الطلبات الواردة. يمكنك استخدام عدادات Avg لمعرفة العمليات التي لا يستطيع القرص معالجتها بالضبط. طول قائمة انتظار قراءة القرص (قراءة قائمة انتظار الطلبات) ومتوسط. طول قائمة انتظار القرص رايت (كتابة قائمة انتظار الطلب).
      متوسط ​​القيمة. لا يتم قياس طول قائمة انتظار القرص ، ولكن يتم حسابه وفقًا لقانون ليتل من النظرية الرياضية لقوائم الانتظار. وفقًا لهذا القانون ، فإن عدد الطلبات التي تنتظر معالجتها ، في المتوسط ​​، يساوي تكرار الطلبات الواردة ، مضروبًا في وقت معالجة الطلب. أولئك. في حالتنا متوسط. طول قائمة انتظار القرص = (عمليات نقل القرص / ثانية) * (متوسط ​​القرص بالثانية / النقل).

      أغسطس. يُعطى طول قائمة انتظار القرص كأحد العدادات الرئيسية لتحديد عبء العمل على النظام الفرعي للقرص ، ومع ذلك ، لتقديره بشكل مناسب ، من الضروري تمثيل الهيكل المادي لنظام التخزين بدقة. على سبيل المثال ، بالنسبة لقرص ثابت واحد ، تعتبر القيمة الأكبر من 2 حرجة ، وإذا كان القرص موجودًا على مجموعة RAID مكونة من 4 أقراص ، فيجب أن تقلق إذا كانت القيمة أكبر من 4 * 2 = 8.

      Zabbix: perf_counter [LogicalDisk (_Total) Avg. طول قائمة انتظار القرص] ، ومن المهم أيضًا تتبع القرص المطلوب ، على سبيل المثال: perf_counter [LogicalDisk (C:) Avg. طول قائمة انتظار القرص]

  2. مكبر الصوت : يدعم، مع دعم ميكروفون مدمج لمنع الضوضاء
    1. صفحات / ثانية
      يعرض عدد الصفحات التي قرأها SQL Server من القرص أو كتبها إلى القرص لحل عمليات الوصول إلى صفحات الذاكرة التي لم يتم تحميلها في الذاكرة الرئيسية وقت الوصول. هذه القيمة هي مجموع قيم إدخال الصفحات في الثانية وإخراج الصفحات في الثانية ، وتأخذ أيضًا في الاعتبار الترحيل (التبديل / التبديل) لذاكرة التخزين المؤقت للنظام للوصول إلى ملفات بيانات التطبيق. ويتضمن أيضًا ترحيل الملفات المعينة للذاكرة غير المخزنة مؤقتًا. هذا هو العداد الرئيسي الذي يجب مراقبته إذا كنت تواجه استخدامًا عاليًا للذاكرة وما يرتبط بها من ترحيل مفرط. يميز هذا العداد مقدار المبادلة ويجب أن تكون قيمته العادية (وليس الذروة) قريبة من الصفر. تشير الزيادة في المبادلة إلى الحاجة إلى زيادة ذاكرة الوصول العشوائي أو تقليل عدد التطبيقات التي تعمل على الخادم.

      Zabbix: perf_counter [MemoryPages / sec] مثال الزناد:
      {NOTE_NAME: perf_counter [MemoryPages / sec] .min (5m)}> 1000 ، معلومات المستوى

    2. أخطاء الصفحة / ثانية

      هذه هي قيمة عداد أخطاء الصفحة. يحدث خطأ صفحة عندما تشير إحدى العمليات إلى صفحة ذاكرة ظاهرية ليست موجودة في مجموعة العمل من ذاكرة الوصول العشوائي. يأخذ هذا العداد في الاعتبار كل من أخطاء الصفحة التي تتطلب الوصول إلى القرص وتلك التي تسببها الصفحة خارج مجموعة العمل في ذاكرة الوصول العشوائي. يمكن لمعظم المعالجات معالجة أخطاء الصفحة من النوع XNUMX دون تأخير كبير. ومع ذلك ، فإن معالجة أخطاء الصفحة من النوع XNUMX ، والتي تتطلب الوصول إلى القرص ، يمكن أن تتسبب في حدوث تأخيرات كبيرة.

      Zabbix: perf_counter [أخطاء MemoryPage / ثانية] مثال الزناد:
      {NODE_NAME: perf_counter [أخطاء MemoryPage / ثانية] .min (5 م)}> 1000 ، معلومات المستوى

    3. البايت المتوفرة

      يتتبع مقدار الذاكرة بالبايت المتاحة لتشغيل العمليات المختلفة. الأرقام المنخفضة تعني ذاكرة منخفضة. الحل هو زيادة الذاكرة. يجب أن يكون هذا العداد في معظم الحالات أعلى من 5000 كيلوفولت باستمرار.
      من المنطقي تعيين الحد الأدنى للميغابايت المتاحة يدويًا للأسباب التالية:

      • توفر 50٪ من الذاكرة الخالية = ممتاز
      • 25٪ ذاكرة متوفرة = تحتاج إلى اهتمام
      • 10٪ مجاني = مشاكل محتملة
      • أقل من 5٪ من الذاكرة المتوفرة = ضروري للسرعة ، تحتاج إلى التدخل.
      Zabbix: perf_counter [MemoryAvailable Bytes]

  3. المعالج (الإجمالي):٪ وقت المعالج
    يوضح هذا العداد النسبة المئوية للوقت الذي كان المعالج مشغولاً فيه بتنفيذ العمليات لمؤشرات الترابط غير الخاملة (مؤشر ترابط غير خامل). يمكن اعتبار هذه القيمة جزءًا صغيرًا من الوقت المطلوب لأداء عمل مفيد. يمكن تعيين كل معالج إلى مؤشر ترابط خامل يستهلك دورات معالج غير منتجة لا تستخدمها مؤشرات الترابط الأخرى. يتميز هذا العداد بقمم قصيرة يمكن أن تصل إلى 100 بالمائة. ومع ذلك ، إذا كانت هناك فترات طويلة يكون فيها استخدام المعالج أعلى من 80 بالمائة ، فسيكون النظام أكثر كفاءة عند استخدام المزيد من المعالجات.

    Zabbix: perf_counter [Processor (_Total)٪ Processor Time] ، هنا يمكن أيضًا عرضها بواسطة النوى
    مثال الزناد:
    {NODE_NAME: perf_counter [Processor (_Total)٪ Processor Time] .min (5m)}> 80، level-info

  4. واجهة الشبكة (*): إجمالي وحدات البايت / ثانية
    العدد الإجمالي للبايتات المرسلة والمستلمة في الثانية عبر جميع الواجهات. هذا هو عرض النطاق الترددي للواجهة (بالبايت). من الضروري مقارنة قيمة هذا العداد مع الحد الأقصى لعرض النطاق الترددي لبطاقة الشبكة. بشكل عام ، يجب ألا يُظهر هذا العداد أكثر من 50٪ من استخدام عرض النطاق الترددي لمحول الشبكة.
    Zabbix: perf_counter [واجهة الشبكة (*) البايت المرسلة / ثانية]
  5. خادم MS SQL: طرق الوصول
    يوفر كائن طرق الوصول في SQL Server عدادات للمساعدة في تعقب الوصول إلى البيانات المنطقية داخل قاعدة بيانات. يتم التحكم في الوصول المادي إلى صفحات قاعدة البيانات على القرص بواسطة عدادات إدارة المخزن المؤقت. تساعدك مراقبة طرق الوصول إلى البيانات في قاعدة البيانات على تحديد ما إذا كان بإمكانك تحسين أداء الاستعلام عن طريق إضافة أو تغيير الفهارس أو إضافة أو نقل أقسام أو إضافة ملفات أو مجموعات من الملفات أو إلغاء تجزئة الفهارس أو تغيير نص الاستعلام. يمكنك أيضًا استخدام العدادات الموجودة في كائن طرق الوصول لمراقبة حجم البيانات والفهارس والمساحة الخالية في قاعدة البيانات ، والتحكم في الحجم والتجزئة لكل مثيل خادم. يمكن أن يؤدي تجزئة المؤشر المفرط إلى تدهور الأداء بشكل كبير.

    1. تقسيم الصفحة / ثانية
      عدد فواصل الصفحات في الثانية التي حدثت نتيجة لحدوث تجاوزات لصفحة الفهرس. تعني القيمة الكبيرة لهذا المؤشر أن SQL Server ينفذ عددًا كبيرًا من العمليات كثيفة الاستخدام للموارد لتقسيم الصفحات ونقل جزء من صفحة موجودة إلى موقع جديد عند إجراء عمليات الإدراج والتحديث. يجب تجنب مثل هذه العمليات كلما أمكن ذلك. يمكنك محاولة حل المشكلة بطريقتين:
      - إنشاء فهرس متفاوت في أعمدة الزيادة التلقائية. في هذه الحالة ، لن يتم وضع الإدخالات الجديدة داخل الصفحات التي تشغلها البيانات بالفعل ، ولكنها ستشغل بالتتابع صفحات جديدة ؛
      - إعادة بناء الفهارس بزيادة قيمة معامل Fillfactor. يسمح هذا الخيار بحجز مساحة خالية في صفحات الفهرس للبيانات الجديدة دون الحاجة إلى ترقيم الصفحات.
      Zabbix: perf_counter ["MSSQL $ InstanceName: طرق الوصول تقسيمات الصفحة في الثانية"، 30] مثال الزناد: {NODE_NAME: perf_counter ["MSSQL $ INStance_NAME: طرق الوصول إلى تقسيمات الصفحة / ثانية"، 30] .last ()}> {NODE_NAME: perf_counter ["MSSQL $ INStance_NAME: SQL StatisticsBatch Orders / sec"، 30] .last ()} / 5 معلومات مستوى
    2. عمليات مسح كاملة / ثانية
      عدد عمليات الفحص الكاملة غير المحدودة في الثانية. تتضمن هذه العمليات عمليات مسح الجدول الأساسي ومسح الفهرس الكامل. قد تشير الزيادة المستقرة في هذا المؤشر إلى تدهور النظام (نقص الفهارس الضرورية ، وتجزئةها القوية ، وعدم استخدام الفهارس الموجودة بواسطة المُحسِّن ، ووجود فهارس غير مستخدمة). ومع ذلك ، تجدر الإشارة إلى أن الفحص الكامل على الطاولات الصغيرة ليس سيئًا دائمًا ، لأنه إذا كان بإمكانك وضع الجدول بأكمله في ذاكرة الوصول العشوائي ، فسيكون إجراء مسح كامل أسرع. ولكن في معظم الحالات ، يشير النمو المستقر لهذا العداد إلى تدهور النظام. كل هذا ينطبق فقط على أنظمة OLTP. في أنظمة OLAP ، يعد الفحص الكامل المستمر أمرًا طبيعيًا.
      Zabbix: perf_counter ["MSSQL $ InstanceName: Access MethodsFull Scans / sec"، 30]

  6. خادم MS SQL: مدير المخزن المؤقت
    يوفر كائن Buffer Manager عدادات لمراقبة كيفية استخدام SQL Server للموارد التالية:
    - ذاكرة لتخزين صفحات البيانات ؛
    - العدادات المستخدمة لمراقبة الإدخال / الإخراج الفعلي عندما يقرأ خادم SQL صفحات قاعدة البيانات ويكتبها ؛
    - توسيع تجمع المخزن المؤقت لتوسيع ذاكرة التخزين المؤقت باستخدام ذاكرة سريعة غير متطايرة ، مثل محركات الأقراص ذات الحالة الصلبة (SSD) ؛
    - تساعد مراقبة الذاكرة والعدادات التي يستخدمها SQL Server في الحصول على المعلومات التالية ؛
    - هل هناك أي "اختناقات" ناجمة عن نقص في الذاكرة الجسدية. إذا كان لا يمكن التخزين المؤقت البيانات التي يتم الوصول إليها بشكل متكرر ، يتم فرض SQL Server لقراءتها من القرص؛
    - ما إذا كان من الممكن زيادة كفاءة تنفيذ الاستعلام عن طريق زيادة حجم الذاكرة أو تخصيص ذاكرة إضافية للتخزين المؤقت للبيانات أو تخزين الهياكل الداخلية لـ SQL Server ؛
    كم مرة يقرأ SQL Server البيانات من القرص. مقارنة بالعمليات الأخرى ، مثل الوصول إلى الذاكرة ، يستغرق الإدخال / الإخراج الفعلي وقتًا أطول. يمكن أن يؤدي تقليل الإدخال / الإخراج إلى تحسين أداء الاستعلام.

    1. ضرب العازلة ذاكرة التخزين المؤقت الراديو
      يشير إلى مدى إمكانية تخصيص SQL Server للبيانات في المخزن المؤقت لذاكرة التخزين المؤقت. كلما زادت هذه القيمة ، كان ذلك أفضل. لكي يتمكن SQL Server من الوصول إلى صفحات البيانات بكفاءة ، يجب أن تكون في مخزن مؤقت لذاكرة التخزين المؤقت ويجب ألا تكون هناك عمليات إدخال / إخراج فعلية (I / O). إذا كان هناك انخفاض ثابت في متوسط ​​قيمة هذا العداد ، فيجب أن تفكر في إضافة ذاكرة الوصول العشوائي. يجب أن يكون هذا المؤشر دائمًا أعلى من 90٪ لأنظمة OLTP وأعلى من 50٪ لأنظمة OLAP.
      Zabbix: perf_counter ["MSSQL $ INSTANCE_NAME: نسبة عدد مرات دخول ذاكرة التخزين المؤقت لـ Buffer ManagerBuffer"، 30] أمثلة على الزناد: {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: نسبة إصابة ذاكرة التخزين المؤقت لـ Buffer ManagerBuffer" ، 30] .last ()} <70 ، مستوى مرتفع
      и
      {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: نسبة عدد مرات دخول ذاكرة التخزين المؤقت لـ Buffer ManagerBuffer" ، 30] .last ()} <80 ، مستوى متوسط
    2. العمر المتوقع للصفحة
      يشير إلى المدة التي ستبقى فيها الصفحة بشكل دائم في الذاكرة بحالتها الحالية. إذا استمرت القيمة في الانخفاض ، فهذا يعني أن النظام يفرط في استخدام تجمع المخزن المؤقت. وبالتالي ، يمكن أن تتسبب عملية الذاكرة في حدوث مشكلات تؤدي إلى تدهور الأداء. تجدر الإشارة إلى أنه لا يوجد مؤشر عالمي يمكن الحكم عليه بشكل لا لبس فيه أن النظام يسيء استخدام تجمع المخزن المؤقت (مؤشر 300 ثانية عفا عليه الزمن مع MS SQL Server 2012).
      Zabbix: perf_counter ["MSSQL $ INSTENTION_NAME: متوسط ​​العمر المتوقع لصفحة مدير المخزن المؤقت"، 30] مثال الزناد: {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: متوسط ​​العمر المتوقع لصفحة مدير المخزن المؤقت" ، 30] .last ()} <5 ، معلومات المستوى

  7. MS SQL Server: إحصائيات عامة
    يوفر كائن الإحصائيات العامة في SQL Server عدادات تسمح لك بمراقبة نشاط الخادم ككل ، مثل عدد الاتصالات المتزامنة وعدد المستخدمين الذين يتصلون بالكمبيوتر الذي يشغل مثيل SQL Server أو يفصلون عنه في الثانية. هذه المقاييس مفيدة في أنظمة معالجة المعاملات الكبيرة عبر الإنترنت (OLTP) حيث يتصل عدد كبير من العملاء باستمرار ويفصلون عن مثيل SQL Server.

    1. تم حظر العملية
      عدد العمليات المحظورة حاليًا.
      Zabbix: perf_counter ["MSSQL $ INSPECTION_NAME: تم منع العمليات الإحصائية العامة"، 30] مثال الزناد: ({NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: تم حظر العمليات الإحصائية العامة"، 30] .min (2m، 0)}> = 0)
      و ({NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: تم حظر العمليات الإحصائية العامة" ، 30] .time (0)}> = 50000)
      و ({NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: تم حظر العمليات الإحصائية العامة" ، 30]. time (0)} <= 230000) ، معلومات المستوى (هناك قيود تنبيه من الساعة 05:00 إلى 23:00)
    2. اتصالات المستخدم
      عدد المستخدمين المتصلين حاليًا بـ SQL Server.
      Zabbix: perf_counter ["MSSQL $ INSPECTION_NAME: إحصائيات عامة اتصالات المستخدم"، 30]

  8. خادم MS SQL: أقفال
    يوفر كائن Locks في Microsoft SQL Server معلومات حول أقفال SQL Server التي تم الحصول عليها على أنواع الموارد الفردية. يتم إصدار التأمين على موارد SQL Server ، مثل الصفوف التي تمت قراءتها أو تعديلها بواسطة معاملة ، لمنع المعاملات المتعددة من استخدام الموارد في نفس الوقت. على سبيل المثال ، إذا تم الحصول على قفل حصري (X) بواسطة معاملة في صف في جدول ، فلا يمكن لأي معاملة أخرى تعديل هذا الصف حتى يتم تحرير القفل. يؤدي تقليل استخدام الأقفال إلى زيادة التزامن ، مما يؤدي إلى تحسين الأداء العام. يمكن تتبع مثيلات متعددة لكائن Locks في نفس الوقت ، كل منها سيمثل قفلًا على نوع مختلف من الموارد.

    1. متوسط ​​وقت الانتظار (مللي ثانية)
      متوسط ​​وقت الانتظار (بالملي ثانية) لجميع طلبات التأمين التي تتطلب انتظارًا. يقيس هذا العداد متوسط ​​عدد عمليات المستخدم التي يتعين عليها الانتظار للحصول على قفل على مورد. تعتمد القيمة القصوى المسموح بها لهذا العداد كليًا على مهمتك ، فمن الصعب تحديد متوسط ​​القيمة لجميع التطبيقات هنا. إذا كان هذا العداد مرتفعًا جدًا ، فقد يعني ذلك حدوث مشكلات في الأقفال في قاعدة البيانات الخاصة بك.
      Zabbix: perf_counter ["MSSQL $ INSTANCE_NAME: Locks (_Total) متوسط ​​وقت الانتظار (مللي ثانية)"، 30] مثال الزناد: {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: Locks (_Total) متوسط ​​وقت الانتظار (مللي ثانية)" ، 30] .last ()}> = 500 ، معلومات المستوى
    2. قفل وقت الانتظار (مللي ثانية)
      إجمالي وقت انتظار القفل (بالملي ثانية) في الثانية الأخيرة.
      Zabbix: perf_counter ["MSSQL $ INSTANCE_NAME: Locks (_Total) Lock Wait Time (ms)"، 30]
    3. قفل ينتظر / ثانية
      عدد المرات في الثانية الأخيرة التي اضطر فيها مؤشر ترابط إلى انتظار طلب قفل.
      Zabbix: perf_counter ["MSSQL $ INSTANCE_NAME: Locks (_Total) Lock Waits / sec"، 30]
    4. تأمين المهلات / ثانية
      عدد مرات إعادة المحاولة عندما لا يمكن الحصول على القفل عن طريق round-robin. تحدد قيمة معلمة تكوين عداد الزيادة والنقصان في SQL Server عدد "المنعطفات" لمؤشر الترابط (يدور) قبل انقضاء مهلة مؤشر الترابط وانتقاله خاملاً.
      Zabbix: perf_counter ["MSSQL $ INSTANCE_NAME: تأمين (_Total) مهلات القفل / ثانية"، 30] مثال الزناد: {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: Locks (_Total) Locks (_Total) Lock Timeouts / sec"، 30] .last ()}> 1000 ، معلومات المستوى
    5. طلبات القفل / ثانية
      عدد الطلبات في الثانية لنوع القفل المحدد.
      Zabbix: perf_counter ["MSSQL $ INSTANCE_NAME: تأمين (_ إجمالي) طلبات القفل / ثانية"، 30] مثال الزناد: {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: Locks (_Total) Lock Orders / sec"، 30] .last ()}> 500000 ، مستوى المعلومات
    6. عدد القفل من Deadlocks / ثانية
      عدد طلبات التأمين في الثانية التي تؤدي إلى طريق مسدود. يشير deadlocks إلى الاستعلامات المشوهة التي تحظر الموارد المشتركة.
      Zabbix: perf_counter ["MSSQL $ INSTENTION_NAME: عدد حالات التوقف التام في الثانية" ، 30] مثال الزناد: {NODE_NAME: perf_counter ["MSSQL $ INSPECTION_NAME: Locks (_Total) عدد مرات التوقف التام في الثانية" ، 30] .last ()}> 1 ، مستوى مرتفع

  9. خادم MS SQL: مدير الذاكرة
    يوفر كائن إدارة الذاكرة في Microsoft SQL Server عدادات لمراقبة استخدام الذاكرة على مستوى الخادم. يمكن أن تساعد مراقبة استخدام الذاكرة على مستوى الخادم لتقييم نشاط المستخدم واستخدام الموارد في تحديد الاختناقات في الأداء. يمكن أن يساعد عنصر التحكم في الذاكرة الذي يستخدمه مثيل SQL Server في تحديد:
    - ما إذا كان هناك نقص في الذاكرة الفعلية غير الكافية لتخزين البيانات التي يتم الوصول إليها بشكل متكرر في ذاكرة التخزين المؤقت. في حالة عدم وجود ذاكرة كافية ، يجب على SQL Server استرداد البيانات من القرص ؛
    - ما إذا كان يمكن تحسين أداء الاستعلام إذا تمت إضافة المزيد من الذاكرة أو توفر المزيد من الذاكرة للتخزين المؤقت للبيانات أو الهياكل الداخلية لـ SQL Server.

    1. منح الذاكرة المتميزة
      يحدد العدد الإجمالي للعمليات التي حصلت على ذاكرة مساحة العمل بنجاح. مع انخفاض ثابت في المؤشر ، من الضروري زيادة ذاكرة الوصول العشوائي.
      Zabbix: perf_counter ["MSSQL $ INSTENTION_NAME: Memory ManagerMemory Grants Outstanding"، 30]
    2. منح الذاكرة معلقة
      يشير إلى العدد الإجمالي للعمليات التي تنتظر منح الذاكرة العاملة. مع النمو المستقر للمؤشر ، من الضروري زيادة ذاكرة الوصول العشوائي.
      Zabbix: perf_counter ["MSSQL $ InstanceName: Memory ManagerMemory Grants Pending"، 30]

  10. MS SQL Server: الإحصائيات
    يوفر كائن الإحصائيات في Microsoft SQL Server عدادات لمراقبة الترجمة وأنواع الاستعلام المرسلة إلى مثيل SQL Server. تمنحك مراقبة عدد عمليات التجميع وإعادة التحويل البرمجي للاستعلام وعدد الدفعات التي يتلقاها مثيل SQL Server فكرة عن مدى سرعة تنفيذ SQL Server لاستعلامات المستخدم ومدى كفاءة مُحسِّن الاستعلام في معالجتها.

    1. الطلبات المجمعة / ثانية
      عدد حزم أوامر Transact-SQL المتلقاة في الثانية. تتأثر هذه الإحصائيات بأي حدود (الإدخال / الإخراج ، وعدد المستخدمين ، وحجم ذاكرة التخزين المؤقت ، وتعقيد الاستعلام ، وما إلى ذلك). يشير العدد الكبير من طلبات الحزم إلى إنتاجية عالية.
      Zabbix: perf_counter ["MSSQL $ InstanceName: SQL StatisticsBatch Request / sec"، 30]

بالإضافة إلى كل ما سبق ، يمكنك أيضًا تكوين عناصر بيانات أخرى (بالإضافة إلى إنشاء مشغلات عليها بإشعار لاحق). على سبيل المثال:
1) مساحة حرة على القرص
2) أحجام ملفات بيانات قاعدة البيانات وسجل السجل
إلخ
ومع ذلك ، فإن كل هذه المؤشرات لا تظهر مشكلة الاستعلامات في الوقت الفعلي.
للقيام بذلك ، تحتاج إلى إنشاء عدادات خاصة بك.
لأسباب تتعلق بالسرية ، لن أعطي أمثلة على مثل هذه العدادات. علاوة على ذلك ، تم تكوينها بشكل فريد لكل نظام. لكني ألاحظ أنه بالنسبة لأنظمة مثل 1C و 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) وإنشاء ملفين بامتداد ps2 (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 = PARAMETER_NAME_NUMBER_of_EXECUTED_QUERY ، بوويرشيل -لا يوجد ملف تعريف -تجاوز سياسة التنفيذ -الملف FULL_PATHzabbixconfuserparams.dFILE_NAME_FOR_EXECUTED_QUERY.ps1
UserParameter = PARAMETER_NAME_NUMBER_of_PENDING_REQUESTS ، بوويرشيل -لا يوجد ملف تعريف -تجاوز تنفيذ السياسة -الملف FULL_PATHzabbixconfuserparams.dFILE_NAME_FOR_PENDING_REQUESTS.ps1
بعد ذلك ، نقوم بحفظ ملف .conf وإعادة تشغيل وكيل Zabbix.
بعد ذلك ، نضيف عنصرين جديدين إلى Zabbix (في هذه الحالة ، الأسماء والمفتاح هي نفسها):
NAME_PARAMETER_NUMBER_PERFORMED_QUERY
NAME_PARAMETER_NUMBER_PENDING_REQUESTS
الآن يمكنك إنشاء الرسوم البيانية والمشغلات على العناصر المخصصة التي تم إنشاؤها.

إذا ارتفع عدد الطلبات المعلقة بشكل حاد ، فيمكن أن يعرض الاستعلام التالي جميع الطلبات قيد التشغيل والمعلقة في وقت معين مع تفاصيل من مكان وتحت أي تسجيل يتم تنفيذ الطلب ، والنص وخطة الاستعلام ، بالإضافة إلى تفاصيل أخرى:
قانون

/*Активные, готовые к выполнению и ожидающие запросы, а также те, что явно блокируют другие сеансы*/
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- موصل- 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. يسمح لك هذا الأسلوب بإعلام المسؤولين بالمشكلات المختلفة في الوقت الفعلي أو بعد وقت معين. وبالتالي ، فإن هذا النهج يسمح بتقليل حدوث مشكلة حرجة في المستقبل وإيقاف تشغيل DBMS والخادم ، مما يحمي بدوره الإنتاج من إيقاف عمليات العمل.
المقال السابق: العمل الروتيني مع قاعدة بيانات نظام المعلومات 24 × 7 في MS SQL Server

مصادر:

» Zabbix 3.4 تحديث
» عدادات الأداء
» مركز الأداء لقاعدة بيانات Azure SQL و SQL Server Database Engine
» SQL لايف ستايل
» مهارات SQL
» مايكروسوفت TechNet
» تحليل استخدام الذاكرة
» تحليل الأداء
» توثيق SQL
» ملاحظات Windows

المصدر: www.habr.com

إضافة تعليق