it-swarm.asia

كيفية تحديد الاستعلام الذي يملأ سجل المعاملات tempdb؟

أود أن أعرف كيفية تحديد الاستعلام الدقيق أو proc المخزن الذي يملأ بالفعل سجل المعاملات لقاعدة بيانات TEMPDB.

67
prasanth

من http://www.sqlservercentral.com/scripts/tempdb/72007/

;WITH task_space_usage AS (
    -- SUM alloc/delloc pages
    SELECT session_id,
           request_id,
           SUM(internal_objects_alloc_page_count) AS alloc_pages,
           SUM(internal_objects_dealloc_page_count) AS dealloc_pages
    FROM sys.dm_db_task_space_usage WITH (NOLOCK)
    WHERE session_id <> @@SPID
    GROUP BY session_id, request_id
)
SELECT TSU.session_id,
       TSU.alloc_pages * 1.0 / 128 AS [internal object MB space],
       TSU.dealloc_pages * 1.0 / 128 AS [internal object dealloc MB space],
       EST.text,
       -- Extract statement from sql text
       ISNULL(
           NULLIF(
               SUBSTRING(
                 EST.text, 
                 ERQ.statement_start_offset / 2, 
                 CASE WHEN ERQ.statement_end_offset < ERQ.statement_start_offset 
                  THEN 0 
                 ELSE( ERQ.statement_end_offset - ERQ.statement_start_offset ) / 2 END
               ), ''
           ), EST.text
       ) AS [statement text],
       EQP.query_plan
FROM task_space_usage AS TSU
INNER JOIN sys.dm_exec_requests ERQ WITH (NOLOCK)
    ON  TSU.session_id = ERQ.session_id
    AND TSU.request_id = ERQ.request_id
OUTER APPLY sys.dm_exec_sql_text(ERQ.sql_handle) AS EST
OUTER APPLY sys.dm_exec_query_plan(ERQ.plan_handle) AS EQP
WHERE EST.text IS NOT NULL OR EQP.query_plan IS NOT NULL
ORDER BY 3 DESC;

[~ # ~] تحرير [~ # ~]

كما أشار مارتن في تعليق ، فإن هذا لن يجد معاملات نشطة تشغل مساحة في tempdb ، فإنه سيجد فقط نشطًا الاستعلامات التي تستخدم حاليًا مساحة هناك (والمتهمين المحتملون لاستخدام السجل الحالي). لذلك قد تكون هناك معاملة مفتوحة ولكن الاستعلام الفعلي الذي يسبب المشكلة لم يعد قيد التشغيل.

يمكنك تغيير inner join على sys.dm_exec_requests إلى left outer join ، فسوف تُرجع صفوفًا لجلسات لا تعمل حاليًا بطلبات بحث نشطة.

نشر الاستعلام مارتن ...

SELECT database_transaction_log_bytes_reserved,session_id 
  FROM sys.dm_tran_database_transactions AS tdt 
  INNER JOIN sys.dm_tran_session_transactions AS tst 
  ON tdt.transaction_id = tst.transaction_id 
  WHERE database_id = 2;

... ستحدد session_ids مع المعاملات النشطة التي تشغل مساحة السجل ، ولكنك لن تكون بالضرورة قادرًا على تحديد الاستعلام الفعلي الذي تسبب في المشكلة ، لأنه إذا لم يكن قيد التشغيل الآن ، فلن يتم تسجيله في الاستعلام أعلاه للطلبات النشطة. قد تكون قادرًا على التحقق من أحدث الاستعلام بشكل تفاعلي باستخدام DBCC INPUTBUFFER ولكنه قد لا يخبرك بما تريد سماعه. يمكنك الانضمام الخارجي بطريقة مماثلة لالتقاط تلك التي تعمل بنشاط ، على سبيل المثال:

SELECT tdt.database_transaction_log_bytes_reserved,tst.session_id,
       t.[text], [statement] = COALESCE(NULLIF(
         SUBSTRING(
           t.[text],
           r.statement_start_offset / 2,
           CASE WHEN r.statement_end_offset < r.statement_start_offset
             THEN 0
             ELSE( r.statement_end_offset - r.statement_start_offset ) / 2 END
         ), ''
       ), t.[text])
     FROM sys.dm_tran_database_transactions AS tdt
     INNER JOIN sys.dm_tran_session_transactions AS tst
     ON tdt.transaction_id = tst.transaction_id
         LEFT OUTER JOIN sys.dm_exec_requests AS r
         ON tst.session_id = r.session_id
         OUTER APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
     WHERE tdt.database_id = 2;

يمكنك أيضا استخدام DMV sys.dm_db_session_space_usage لمعرفة الاستخدام العام للمساحة حسب الجلسة (ولكن مرة أخرى قد لا تحصل على نتائج صالحة للاستعلام ؛ إذا لم يكن الاستعلام نشطًا ، فقد لا يكون ما تحصل عليه هو الجاني الفعلي).

;WITH s AS
(
    SELECT 
        s.session_id,
        [pages] = SUM(s.user_objects_alloc_page_count 
          + s.internal_objects_alloc_page_count) 
    FROM sys.dm_db_session_space_usage AS s
    GROUP BY s.session_id
    HAVING SUM(s.user_objects_alloc_page_count 
      + s.internal_objects_alloc_page_count) > 0
)
SELECT s.session_id, s.[pages], t.[text], 
  [statement] = COALESCE(NULLIF(
    SUBSTRING(
        t.[text], 
        r.statement_start_offset / 2, 
        CASE WHEN r.statement_end_offset < r.statement_start_offset 
        THEN 0 
        ELSE( r.statement_end_offset - r.statement_start_offset ) / 2 END
      ), ''
    ), t.[text])
FROM s
LEFT OUTER JOIN 
sys.dm_exec_requests AS r
ON s.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
ORDER BY s.[pages] DESC;

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

بعض النصائح لتقليل استخدام tempdp

  1. استخدام عدد أقل من جداول #temp ومتغيراتtable
  2. التقليل من صيانة المؤشر المتزامن وتجنب SORT_IN_TEMPDB الخيار إذا لم يكن هناك حاجة
  3. تجنب المؤشرات غير الضرورية ؛ تجنب المؤشرات الثابتة إذا كنت تعتقد أن هذا قد يكون اختناق ، لأن المؤشرات الثابتة تستخدم جداول العمل في tempdb - على الرغم من أن هذا هو نوع المؤشر الذي أوصي به دائمًا إذا لم يكن tempdb عنق زجاجة
  4. حاول تجنب البكرات (مثل CTEs الكبيرة التي يتم الرجوع إليها عدة مرات في الاستعلام)
  5. لا تستخدم MARS
  6. اختبر تمامًا استخدام مستويات عزل اللقطة/RCSI - لا تقم بتشغيلها فقط لجميع قواعد البيانات حيث قيل لك أنها أفضل من NOLOCK (إنها كذلك ، ولكنها ليست مجانية)
  7. في بعض الحالات ، قد يبدو غير بديهي ، ولكن استخدم more الجداول المؤقتة. على سبيل المثال قد يكون تقسيم استعلام هائل إلى أجزاء أقل كفاءة قليلاً ، ولكن إذا كان بإمكانه تجنب حدوث تسرب كبير للذاكرة إلى tempdb لأن الاستعلام الأكبر والأكبر يتطلب منح ذاكرة كبيرة جدًا ...
  8. تجنب تمكين مشغلات العمليات المجمعة
  9. تجنب الإفراط في استخدام أنواع LOB (الأنواع القصوى ، XML ، إلخ) كمتغيرات محلية
  10. جعل المعاملات قصيرة وحلوة
  11. لا تقم بتعيين tempdp ليكون قاعدة البيانات الافتراضية للجميع -

قد تضع في اعتبارك أيضًا أن استخدام سجل tempdp قد يكون ناتجًا عن عمليات داخلية لا تملك سيطرة كبيرة أو لا يمكنك التحكم بها - على سبيل المثال بريد قاعدة البيانات وإشعارات الأحداث وإشعارات الاستعلام ووسيط الخدمة تستخدم جميعها tempdb بطريقة ما. يمكنك التوقف عن استخدام هذه الميزات ، ولكن إذا كنت تستخدمها ، فلا يمكنك إملاء كيف ومتى تستخدم tempdb.

76
Aaron Bertrand

https://social.msdn.Microsoft.com/Forums/sqlserver/en-US/17d9f862-b9ae-42de-ada0-4229f56712dc/tempdb-log-filling-cannot-find-how-or-what؟ المنتدى = sqldatabaseengine

 SELECT tst.[session_id],
            s.[login_name] AS [Login Name],
            DB_NAME (tdt.database_id) AS [Database],
            tdt.[database_transaction_begin_time] AS [Begin Time],
            tdt.[database_transaction_log_record_count] AS [Log Records],
            tdt.[database_transaction_log_bytes_used] AS [Log Bytes Used],
            tdt.[database_transaction_log_bytes_reserved] AS [Log Bytes Rsvd],
            SUBSTRING(st.text, (r.statement_start_offset/2)+1,
            ((CASE r.statement_end_offset
                    WHEN -1 THEN DATALENGTH(st.text)
                    ELSE r.statement_end_offset
            END - r.statement_start_offset)/2) + 1) AS statement_text,
            st.[text] AS [Last T-SQL Text],
            qp.[query_plan] AS [Last Plan]
    FROM    sys.dm_tran_database_transactions tdt
            JOIN sys.dm_tran_session_transactions tst
                ON tst.[transaction_id] = tdt.[transaction_id]
            JOIN sys.[dm_exec_sessions] s
                ON s.[session_id] = tst.[session_id]
            JOIN sys.dm_exec_connections c
                ON c.[session_id] = tst.[session_id]
            LEFT OUTER JOIN sys.dm_exec_requests r
                ON r.[session_id] = tst.[session_id]
            CROSS APPLY sys.dm_exec_sql_text (c.[most_recent_sql_handle]) AS st
            OUTER APPLY sys.dm_exec_query_plan (r.[plan_handle]) AS qp
    WHERE   DB_NAME (tdt.database_id) = 'tempdb'
    ORDER BY [Log Bytes Used] DESC
GO
5
Saurabh Sinha

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

يتم ذلك كل 3 دقائق لمدة 40 مرة ، أي ساعتين. قم بتعديل المعلمات كما تراه مناسبًا.

هناك عامل تصفية WHERE> 50 صفحة أدناه قد يرغب الأشخاص في مسحه فقط في حالة وجود الكثير من الجداول الصغيرة. وإلا لن تتمكن من التقاط هذا الفارق الدقيق مع ما هو أدناه ...

استمتع!

DECLARE @minutes_apart INT; SET @minutes_apart = 3
DECLARE @how_many_times INT; SET @how_many_times = 40
--DROP TABLE tempdb..TempDBUsage
--SELECT * FROM tempdb..TempDBUsage
--SELECT session_id, STDEV(pages) stdev_pages FROM tempdb..TempDBUsage GROUP BY session_id HAVING STDEV(pages) > 0 ORDER BY stdev_pages DESC

DECLARE @delay_string NVARCHAR(8); SET @delay_string = '00:' + RIGHT('0'+ISNULL(CAST(@minutes_apart AS NVARCHAR(2)), ''),2) + ':00'
DECLARE @counter INT; SET @counter = 1

SET NOCOUNT ON
if object_id('tempdb..TempDBUsage') is null
    begin
    CREATE TABLE tempdb..TempDBUsage (
        session_id INT, pages INT, num_reads INT, num_writes INT, login_time DATETIME, last_batch DATETIME,
        cpu INT, physical_io INT, hostname NVARCHAR(64), program_name NVARCHAR(128), text NVARCHAR (MAX)
    )
    end
else
    begin
        PRINT 'To view the results run this:'
        PRINT 'SELECT * FROM tempdb..TempDBUsage'
        PRINT 'OR'
        PRINT 'SELECT session_id, STDEV(pages) stdev_pages FROM tempdb..TempDBUsage GROUP BY session_id HAVING STDEV(pages) > 0 ORDER BY stdev_pages DESC'
        PRINT ''
        PRINT ''
        PRINT 'Otherwise manually drop the table by running the following, then re-run the script:'
        PRINT 'DROP TABLE tempdb..TempDBUsage'
        RETURN
    end
--GO
TRUNCATE TABLE tempdb..TempDBUsage
PRINT 'To view the results run this:'; PRINT 'SELECT * FROM tempdb..TempDBUsage'
PRINT 'OR'; PRINT 'SELECT session_id, STDEV(pages) stdev_pages FROM tempdb..TempDBUsage GROUP BY session_id HAVING STDEV(pages) > 0 ORDER BY stdev_pages DESC'
PRINT ''; PRINT ''

while @counter <= @how_many_times
begin
INSERT INTO tempdb..TempDBUsage (session_id,pages,num_reads,num_writes,login_time,last_batch,cpu,physical_io,hostname,program_name,text)
    SELECT PAGES.session_id, PAGES.pages, r.num_reads, r.num_writes, sp.login_time, sp.last_batch, sp.cpu, sp.physical_io, sp.hostname, sp.program_name, t.text
    FROM sys.dm_exec_connections AS r
    LEFT OUTER JOIN master.sys.sysprocesses AS sp on sp.spid=r.session_id
    OUTER APPLY sys.dm_exec_sql_text(r.most_recent_sql_handle) AS t
    LEFT OUTER JOIN (
        SELECT s.session_id, [pages] = SUM(s.user_objects_alloc_page_count + s.internal_objects_alloc_page_count) 
        FROM sys.dm_db_session_space_usage AS s
        GROUP BY s.session_id
        HAVING SUM(s.user_objects_alloc_page_count + s.internal_objects_alloc_page_count) > 0
    ) PAGES ON PAGES.session_id = r.session_id
    WHERE PAGES.session_id IS NOT NULL AND PAGES.pages > 50
    ORDER BY PAGES.pages DESC;
PRINT CONVERT(char(10), @counter) + ': Ran at: ' + CONVERT(char(30), GETDATE())
SET @counter = @counter + 1
waitfor delay @delay_string
end
4
Joe Zee

لسوء الحظ لا يمكن تتبع سجل tempDB مباشرة إلى sessionID الخاص عن طريق عرض العمليات قيد التشغيل.

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

النتائج الموسعة للحدث:

enter image description here

البرنامج النصي لإنشاء الحدث الموسع:

CREATE EVENT SESSION [tempdb_file_size_changed] ON SERVER ADD EVENT 
sqlserver.database_file_size_change(SET collect_database_name=(1)ACTION(sqlserver.client_app_name,sqlserver.client_hostname,sqlserver.is_system,sqlserver.query_hash,sqlserver.session_id,sqlserver.session_nt_username,sqlserver.sql_text,sqlserver.username) WHERE ([database_id]=(2))) ADD TARGETpackage0.event_file(SET filename=N'C:\ExtendedEvents\TempDBGrowth.xel',max_file_size=(100),max_rollover_files=(25)) WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=1 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=ON)
1
Tequila