Udemy
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
Turn what you know into an opportunity and reach millions around the world.
Learn More
Your cart is empty.
Keep shopping
SQL Server Love Linux:效能篇
6 students

SQL Server Love Linux:效能篇

從DBA人員角度切入,深入淺出SQL Server效能調校技巧!
Created byRico Chen
Last updated 12/2020
Chinese (Traditional)

What you'll learn

  • 獲取SQL Server查詢效能知識,搞懂資料庫管理核心
  • 知道如何利用優化過的索引設計提高查詢效能
  • 了解如何快速比較查詢效能,有效追蹤各種成效
  • 搞懂SQL Server等待類型,達到資源利用最大化
  • 釐清SQL Server封鎖和死鎖原因,輕鬆避開效能地雷
  • 學會正確閱讀與優化執行計畫,享受執行計畫所帶來的快感

Course content

6 sections25 lectures5h 23m total length
  • 課程簡介3:53

    課程簡介

  • 效能問題定義2:49
  • 常見效能主因9:31
  • 效能優化步驟9:41
  • SQL Server重要設定5:03
  • 善用擴充事件24:55

    /*

    @Packages: 是 SQL Server 擴充事件物件的容器,不同packages定義不同功能邊界,可以混合使用不同packages.

    如sqlos - SQL Server 作業系統 (SQLOS) 相關的物件。sqlserver - SQL Server 相關的物件。

    package0 - 擴充事件系統物件、這是預設封裝...等

    sys.dm_xe_packages


    @Events:監控特定事件,不同版本的SQL Server,支援的事件也不同


    select *

    from sys.dm_xe_packages pck join sys.dm_xe_objects obj on pck.guid=obj.package_guid

    where

    (pck.capabilities is null or pck.capabilities & 1=0)--exclude private packages

    and

    (pck.capabilities is null or obj.capabilities & 1=0)--exclude private events

    and obj.object_type='event'


    @Predicates:定義事件什麼時候被觸發條件


    @Actions:針對事件進行額外訊息收集,要注意Action會有額外效能成本,

    可能會導致效能大幅下降,如從計畫快取中收集執行計畫


    @Target:當事件被觸發後,目標用於保留原始資料或資料分析操作,

    預設使用ring_buffer即時處理,但空間一滿就會覆蓋最舊資料,

    不適合長期監控,除非選擇文件目標才適合長期監控

    */


    --@監控Deadlock

    --session1

    begin tran


    update DatabaseLog set PostTime=GETDATE()

    where DatabaseLogID=5


    waitfor delay '00:00:03'


    update DatabaseLog set PostTime=GETDATE()

    where DatabaseLogID=6


    rollback


    --session2

    begin tran


    update DatabaseLog set PostTime=GETDATE()

    where DatabaseLogID=6


    waitfor delay '00:00:03'


    update DatabaseLog set PostTime=GETDATE()

    where DatabaseLogID=5


    rollback



    ;with baseEventData

    as

    (

    SELECT 'DeadlockXml'=XEvent.query('(event/data/value/deadlock)[1]')

    ,'BeginTime'= DATEADD(HOUR,8, XEvent.value('(/event/@timestamp)[1]','DATETIMEOFFSET'))

    FROM ( SELECT XEvent.query('.') AS XEvent

           FROM ( SELECT CAST(target_data AS XML) AS TargetData

                  FROM sys.dm_xe_session_targets st

                       JOIN sys.dm_xe_sessions s

                       ON s.address = st.event_session_address

                  WHERE s.name = 'system_health'

                        AND st.target_name = 'ring_buffer'

                  ) AS Data

                  CROSS APPLY

                     TargetData.nodes

                        ('RingBufferTarget/event[@name="xml_deadlock_report"]')

                  AS XEventData ( XEvent )

          ) AS src

    )

    select * from baseEventData

    order by BeginTime desc



    --@監控長時間查詢(5秒)

    IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name = 'long_query_report')

    DROP EVENT SESSION [long_query_report] ON SERVER;

    GO


    CREATE EVENT SESSION [long_query_report] ON SERVER

    ADD EVENT sqlserver.rpc_completed( --監控 rpc_completed

        ACTION(sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname)

    --執行時間>5 sec ,非系統session

        WHERE ( [duration]>(5000000) and database_id=5 and sqlserver.is_system=0 )),

    ADD EVENT sqlserver.sp_statement_completed(

        ACTION(sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname)

        WHERE ( [duration]>(5000000) and database_id=5  )),

    ADD EVENT sqlserver.sql_batch_completed(

        ACTION(sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname)

        WHERE ([duration]>(5000000) and database_id=5 )),

    ADD EVENT sqlserver.sql_statement_completed(

        ACTION(sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname)

        WHERE ( [duration]>(5000000) and database_id=5 ))

    ADD TARGET package0.ring_buffer(SET max_events_limit=(0),max_memory=(1048576) /*1 GB*/)

    WITH (EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)

    GO


    ALTER EVENT SESSION [long_query_report] ON SERVER STATE = START

    GO


    SELECT src.XEvent.value('(event/@timestamp)[1]', 'datetime2') AS datetime_utc,

    CONVERT(datetime2,SWITCHOFFSET(CONVERT(datetimeoffset,src.XEvent.value('(event/@timestamp)[1]', 'datetime2')),DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS datetime_local,

    src.XEvent.value('(event/@name)[1]', 'varchar(50)') AS event_type,

    src.XEvent.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') AS statement,

    src.XEvent.value('(event/data[@name="duration"]/value)[1]', 'bigint')/1000 AS duration_ms,

    src.XEvent.value('(event/data[@name="cpu_time"]/value)[1]', 'bigint')/1000 AS cpu_time_ms,

    src.XEvent.value('(event/data[@name="physical_reads"]/value)[1]', 'bigint') AS physical_reads,

    src.XEvent.value('(event/data[@name="logical_reads"]/value)[1]', 'bigint') AS logical_reads,

    src.XEvent.value('(event/data[@name="writes"]/value)[1]', 'bigint') AS writes,

    src.XEvent.value('(event/data[@name="row_count"]/value)[1]', 'bigint') AS row_count,

    '0x' + src.XEvent.value ('(/event/action[@name="plan_handle"]/value)[1]', 'VARCHAR(1000)') AS [Plan Handle],

    src.XEvent.value('(event/action[@name="database_name"]/value)[1]', 'varchar(255)') AS database_name,

    src.XEvent.value('(event/action[@name="client_hostname"]/value)[1]', 'varchar(255)') AS client_hostname,

    src.XEvent.value('(event/action[@name="client_app_name"]/value)[1]', 'varchar(255)') AS client_app_name

    FROM ( SELECT XEvent.query('.') AS XEvent

           FROM ( SELECT CAST(target_data AS XML) AS TargetData

                  FROM sys.dm_xe_session_targets st

                       JOIN sys.dm_xe_sessions s

                       ON s.address = st.event_session_address

                  WHERE s.name = 'long_query_report'

                        AND st.target_name = 'ring_buffer'

                  ) AS Data

                  CROSS APPLY

                     TargetData.nodes

                        ('RingBufferTarget/event')

                  AS XEventData ( XEvent )

          ) AS src



    --session1

    begin tran

    update DatabaseLog set PostTime=GETDATE()

    where DatabaseLogID=1


    --rollback


    --session2

    select * from DatabaseLog where DatabaseLogID=1



    --@監控查詢逾時

    IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name = 'query_timeouts_report')

    DROP EVENT SESSION [query_timeouts_report] ON SERVER;

    GO


    CREATE EVENT SESSION [query_timeouts_report] ON SERVER

    ADD EVENT sqlserver.sql_statement_completed

    (

    ACTION

    (

    sqlserver.session_id,

    sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname

    )

    WHERE (database_id=5 )

    ),

    ADD EVENT sqlserver.sql_statement_starting

    (

    ACTION

    (

    sqlserver.session_id,

    sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname

    )

    WHERE (database_id=5  )

    )

    ADD TARGET package0.pair_matching

    (

    SET

    begin_event = 'sqlserver.sql_statement_starting',

    begin_matching_actions = 'sqlserver.session_id, sqlserver.tsql_stack',

    end_event = 'sqlserver.sql_statement_completed',

    end_matching_actions = 'sqlserver.session_id, sqlserver.tsql_stack',

    respond_to_memory_pressure = 0

    )

    WITH (MAX_DISPATCH_LATENCY=5 SECONDS, TRACK_CAUSALITY=ON, STARTUP_STATE=OFF)

    GO


    ALTER EVENT SESSION [query_timeouts_report] ON SERVER STATE = START

    GO


    SELECT src.XEvent.value('(event/@timestamp)[1]', 'datetime2') AS datetime_utc,

    CONVERT(datetime2,SWITCHOFFSET(CONVERT(datetimeoffset,src.XEvent.value('(event/@timestamp)[1]', 'datetime2')),DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS datetime_local,

    src.XEvent.value('(event/@name)[1]', 'varchar(50)') AS event_type,

    src.XEvent.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') AS statement,

    src.XEvent.value('(event/action[@name="session_id"]/value)[1]', 'varchar(max)') as session_id,

    src.XEvent.value('(event/action[@name="tsql_stack"]/value)[1]', 'varchar(max)') as tsql_stack,

    '0x' + src.XEvent.value ('(/event/action[@name="plan_handle"]/value)[1]', 'VARCHAR(1000)') AS [Plan Handle],

    src.XEvent.value('(event/action[@name="database_name"]/value)[1]', 'varchar(255)') AS database_name,

    src.XEvent.value('(event/action[@name="client_hostname"]/value)[1]', 'varchar(255)') AS client_hostname,

    src.XEvent.value('(event/action[@name="client_app_name"]/value)[1]', 'varchar(255)') AS client_app_name

    FROM ( SELECT XEvent.query('.') AS XEvent

           FROM ( SELECT CAST(target_data AS XML) AS TargetData

                  FROM sys.dm_xe_session_targets st

                       JOIN sys.dm_xe_sessions s

                       ON s.address = st.event_session_address

                  WHERE s.name = 'query_timeouts_report'

                        AND st.target_name = 'pair_matching'

                  ) AS Data

                  CROSS APPLY

                     TargetData.nodes

                        ('PairingTarget/event')

                  AS XEventData ( XEvent )

          ) AS src





    --@監控長時間封鎖查詢(10秒)

    IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name = 'blocked_process_report')

    DROP EVENT SESSION [blocked_process_report] ON SERVER;

    GO


    CREATE EVENT SESSION [blocked_process_report] ON SERVER

    ADD EVENT sqlserver.blocked_process_report(

        ACTION(sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.tsql_stack,

    sqlserver.username,

    sqlserver.client_app_name,

    sqlserver.client_hostname)

    WHERE ( database_id=5 ))

    ADD TARGET package0.ring_buffer(SET max_events_limit=(0),max_memory=(1048576) /*1 GB*/)

    WITH (EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)

    GO


    EXEC sp_configure 'show advanced options', 1 ;

    GO

    RECONFIGURE ;

    GO

    /* Enabled the blocked process report */

    EXEC sp_configure 'blocked process threshold', '10';

    RECONFIGURE

    GO


    ALTER EVENT SESSION [blocked_process_report] ON SERVER STATE = START

    GO


    SELECT src.XEvent.value('(event/@timestamp)[1]', 'datetime2') AS datetime_utc,

    CONVERT(datetime2,SWITCHOFFSET(CONVERT(datetimeoffset,src.XEvent.value('(event/@timestamp)[1]', 'datetime2')),DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS datetime_local,

    src.XEvent.value('(event/@name)[1]', 'varchar(50)') AS event_type,

    src.XEvent.value('(event[@name="blocked_process_report"]/data[@name="blocked_process"]/value/blocked-process-report)[1]', 'nvarchar(max)') as [blocked_process_report],

    src.XEvent.value('(event[@name="blocked_process_report"]/data[@name="duration"]/value)[1]', 'bigint') as [duration  (ms)],

    src.XEvent.value('(event[@name="blocked_process_report"]/data[@name="object_id"]/value)[1]', 'varchar(50)') as [object_id],

    src.XEvent.value('(event[@name="blocked_process_report"]/data[@name="index_id"]/value)[1]', 'varchar(50)') as [index_id],

    src.XEvent.value('(event/action[@name="tsql_stack"]/value)[1]', 'varchar(max)') as tsql_stack,

    '0x' + src.XEvent.value ('(/event/action[@name="plan_handle"]/value)[1]', 'VARCHAR(1000)') AS [Plan Handle],

    src.XEvent.value('(event/action[@name="database_name"]/value)[1]', 'varchar(255)') AS database_name,

    src.XEvent.value('(event/action[@name="client_hostname"]/value)[1]', 'varchar(255)') AS client_hostname,

    src.XEvent.value('(event/action[@name="client_app_name"]/value)[1]', 'varchar(255)') AS client_app_name

    FROM ( SELECT XEvent.query('.') AS XEvent

           FROM ( SELECT CAST(target_data AS XML) AS TargetData

                  FROM sys.dm_xe_session_targets st

                       JOIN sys.dm_xe_sessions s

                       ON s.address = st.event_session_address

                  WHERE s.name = 'blocked_process_report'

                        AND st.target_name = 'ring_buffer'

                  ) AS Data

                  CROSS APPLY

                     TargetData.nodes

                        ('RingBufferTarget/event')

                  AS XEventData ( XEvent )

          ) AS src



    --session1

    begin tran

    update DatabaseLog set PostTime=GETDATE()

    where DatabaseLogID=1


    --rollback


    --session2

    select * from DatabaseLog where DatabaseLogID=1



    --@監控CPU高成本查詢(50毫秒)

    IF EXISTS (SELECT * FROM sys.server_event_sessions WHERE name = 'expensive_queries_report')

    DROP EVENT SESSION [expensive_queries_report] ON SERVER;

    GO


    CREATE EVENT SESSION [expensive_queries_report] ON SERVER

    ADD EVENT sqlserver.sql_statement_completed

    (

    ACTION (

    sqlserver.database_name,

    sqlserver.sql_text,

    sqlserver.plan_handle,

    sqlserver.client_app_name,

    sqlserver.client_hostname)

    WHERE sqlserver.database_id = 5 AND cpu_time > 50000 /*total ms of CPU time*/)

    ADD TARGET package0.ring_buffer(SET max_events_limit=(0),max_memory=(1048576) /*1 GB*/)

    WITH (EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=5 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=ON,STARTUP_STATE=OFF)

    GO


    ALTER EVENT SESSION [expensive_queries_report] ON SERVER STATE = START

    GO


    SELECT src.XEvent.value('(event/@timestamp)[1]', 'datetime2') AS datetime_utc,

    CONVERT(datetime2,SWITCHOFFSET(CONVERT(datetimeoffset,src.XEvent.value('(event/@timestamp)[1]', 'datetime2')),DATENAME(TzOffset, SYSDATETIMEOFFSET()))) AS datetime_local,

    src.XEvent.value('(event/@name)[1]', 'varchar(50)') AS event_type,

    src.XEvent.value('(event/data[@name="statement"]/value)[1]', 'varchar(max)') AS statement,

    src.XEvent.value('(event/data[@name="duration"]/value)[1]', 'bigint')/1000 AS duration_ms,

    src.XEvent.value('(event/data[@name="cpu_time"]/value)[1]', 'bigint')/1000 AS cpu_time_ms,

    src.XEvent.value('(event/data[@name="physical_reads"]/value)[1]', 'bigint') AS physical_reads,

    src.XEvent.value('(event/data[@name="logical_reads"]/value)[1]', 'bigint') AS logical_reads,

    src.XEvent.value('(event/data[@name="writes"]/value)[1]', 'bigint') AS writes,

    src.XEvent.value('(event/data[@name="row_count"]/value)[1]', 'bigint') AS row_count,

    '0x' + src.XEvent.value ('(/event/action[@name="plan_handle"]/value)[1]', 'VARCHAR(200)') AS [Plan Handle],

    src.XEvent.value('(event/action[@name="database_name"]/value)[1]', 'varchar(255)') AS database_name,

    src.XEvent.value('(event/action[@name="client_hostname"]/value)[1]', 'varchar(255)') AS client_hostname,

    src.XEvent.value('(event/action[@name="client_app_name"]/value)[1]', 'varchar(255)') AS client_app_name

    FROM ( SELECT XEvent.query('.') AS XEvent

           FROM ( SELECT CAST(target_data AS XML) AS TargetData

                  FROM sys.dm_xe_session_targets st

                       JOIN sys.dm_xe_sessions s

                       ON s.address = st.event_session_address

                  WHERE s.name = 'expensive_queries_report'

                        AND st.target_name = 'ring_buffer'

                  ) AS Data

                  CROSS APPLY

                     TargetData.nodes

                        ('RingBufferTarget/event')

                  AS XEventData ( XEvent )

          ) AS src


    SELECT [query_plan] FROM sys.dm_exec_query_plan (0x0600050000877134606f71470400000001000000000000000000000000000000000000000000000000000000);


    SELECT SUM (OrderQty) FROM Sales.SalesOrderDetail

    WHERE CarrierTrackingNumber like '%3c%'

Requirements

  • 知道SQL Server用途
  • 知道Linux用途
  • 知道Hyper-V用途

Description

@耗費了許多功夫將 SQL Server 轉移到 Linux 後 ,就能高枕無憂嗎?

我專為DBA人員而生的SQL Server效能調校課程,帶你搞懂效能地雷並有效避開!

公司為了不付昂貴的授權費於是改用 Linux,但是資料庫出問題時 ···

  • 網絡不穩定、資源不足、突發性大數據量操作.....到底如何快速判斷主因呢?

  • 如何在合理前提下,透過表分割槽、檔案組拆分等操作,提高SQL Server能力?

  • 怎麼樣才能因應Linux及Windows各自的系統優勢,調整效能調校的方法呢?

  • 使用者人數突然暴增時,如何避免出現回應時間大幅降低甚至逾時錯誤的情形?

別擔心,這些問題都將在SQL Server on Linux - 效能篇中一一為你解答!

這堂課中,將為你從執行計畫、索引、鎖定、等待幾個面向切入,介紹常見的效能問題以及對應的解決方法,帶你養成系統性的問題解決思維!

這系列課程由 DBA 角度來看 SQL Server on Linux,絕不單單只有實務上工作技巧,更介紹許多效能調校的核心觀念,就是要讓你知其然,更知其所以然,減少問題定位和排除時間。


@獨家提供SQL Server效能優化實戰技巧

這堂課我將提供許多個人實戰範例獨家優化技巧!當我們面對各種資料庫問題的可能原因時,這些內容將可以協助你更快速的定位與解決問題,也可以避開我曾經踩過的雷!

Who this course is for:

  • 適合中高階DBA,養成完整的系統式思維
  • 適合SQL Server愛好者,從入門到打底完整教學
  • 適合對SQL Server On Linux有興趣者或有需求者
  • 適合對SQL Server效能調校有興趣者,教你快速定位效能問題
  • 適合立志朝高階SQL Server DBA、SQL Server Developer或資料庫架構師的專業人員