Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Lebih lanjut tentang CXPACKET Menunggu:Paralelisme Miring

Dalam posting saya sebelumnya, saya membahas CXPACKET menunggu dan cara untuk mencegah atau membatasi paralelisme. Saya juga menjelaskan bagaimana utas kontrol dalam operasi paralel selalu mendaftarkan CXPACKET menunggu, dan kadang-kadang utas non-kontrol juga dapat mendaftarkan CXPACKET menunggu. Ini bisa terjadi jika salah satu utas diblokir menunggu sumber daya (jadi semua utas lainnya selesai sebelum itu dan mendaftar CXPACKET juga menunggu), atau jika perkiraan kardinalitas salah. Dalam posting ini saya ingin menjelajahi yang terakhir.

Ketika perkiraan kardinalitas salah, utas paralel yang melakukan pekerjaan kueri diberikan jumlah pekerjaan yang tidak merata. Kasus tipikal adalah di mana satu utas diberikan semua pekerjaan, atau jauh lebih banyak pekerjaan daripada utas lainnya. Ini berarti bahwa utas yang selesai memproses barisnya (jika bahkan diberi) sebelum utas paling lambat mendaftarkan CXPACKET dari saat selesai hingga utas paling lambat selesai. Masalah ini dapat menyebabkan ledakan yang tampak di CXPACKET menunggu terjadi dan biasanya disebut paralelisme miring , karena distribusi pekerjaan antara utas paralel miring, tidak merata.

Perhatikan bahwa di SQL Server 2016 SP2 dan SQL Server 2017 RTM CU3, utas konsumen tidak lagi mendaftar CXPACKET menunggu. Mereka mendaftarkan CXCONSUMER menunggu, yang jinak dan dapat diabaikan. Ini untuk mengurangi jumlah menunggu CXPACKET yang dihasilkan, dan yang tersisa lebih mungkin untuk ditindaklanjuti.

Contoh Paralelisme Miring

Saya akan membahas contoh yang dibuat-buat untuk menunjukkan cara mengidentifikasi kasus semacam itu.

Pertama, saya akan membuat skenario di mana tabel memiliki statistik yang sangat tidak akurat, dengan menyetel jumlah baris dan halaman secara manual dalam Statistik PEMBARUAN pernyataan (jangan lakukan ini dalam produksi!):

USE [master];
GO
 
IF DB_ID (N'ExecutionMemory') IS NOT NULL
BEGIN
    ALTER DATABASE [ExecutionMemory] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    DROP DATABASE [ExecutionMemory];
END
GO
 
CREATE DATABASE [ExecutionMemory];
GO
USE [ExecutionMemory];
GO
 
CREATE TABLE dbo.[Test] (
    [RowID] INT IDENTITY,
    [ParentID] INT,
    [CurrentValue] NVARCHAR (100),
    CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED ([RowID]));
GO
 
INSERT INTO dbo.[Test] ([ParentID], [CurrentValue])
SELECT 
    CASE WHEN ([t1].[number] % 3 = 0)
        THEN [t1].[number] – [t1].[number] % 6
        ELSE [t1].[number] END, 
    'Test' + CAST ([t1].[number] % 2 AS VARCHAR(11))
FROM [master].[dbo].[spt_values] AS [t1]
WHERE [t1].[type] = 'P';
GO
 
UPDATE STATISTICS dbo.[Test] ([PK_Test]) WITH ROWCOUNT = 10000000, PAGECOUNT = 1000000;
GO

Jadi meja saya hanya memiliki beberapa ribu baris di dalamnya, tetapi saya telah memalsukannya dengan 10 juta baris.

Sekarang saya akan membuat kueri yang dibuat untuk memilih 500 baris teratas, yang akan paralel karena dianggap ada jutaan baris yang harus dipindai.

USE [ExecutionMemory];
GO
 
SET NOCOUNT ON;
GO
 
DECLARE @CurrentValue NVARCHAR (100);
 
WHILE (1=1)
SELECT TOP (500) 
    @CurrentValue = [CurrentValue]
FROM dbo.[Test]
ORDER BY NEWID() DESC;
GO

Dan atur itu berjalan.

Melihat CXPACKET Menunggu

Sekarang saya dapat melihat CXPACKET menunggu yang terjadi menggunakan skrip sederhana untuk melihat sys.dm_os_waiting_tasks DMV:

SELECT
    [owt].[session_id],
    [owt].[exec_context_id],
    [owt].[wait_duration_ms],
    [owt].[wait_type],
    [owt].[blocking_session_id],
    [owt].[resource_description],
    [er].[database_id],
    [eqp].[query_plan]
FROM sys.dm_os_waiting_tasks [owt]
INNER JOIN sys.dm_exec_sessions [es] ON
    [owt].[session_id] = [es].[session_id]
INNER JOIN sys.dm_exec_requests [er] ON
    [es].[session_id] = [er].[session_id]
OUTER APPLY sys.dm_exec_sql_text ([er].[sql_handle]) [est]
OUTER APPLY sys.dm_exec_query_plan ([er].[plan_handle]) [eqp]
WHERE
    [es].[is_user_process] = 1
ORDER BY
    [owt].[session_id],
    [owt].[exec_context_id];

Jika saya menjalankan ini beberapa kali, akhirnya saya melihat beberapa hasil yang menunjukkan paralelisme miring (saya menanggalkan tautan pegangan rencana kueri dan membatasi deskripsi sumber daya, untuk kejelasan, dan perhatikan saya memasukkan kode untuk mengambil teks SQL jika Anda menginginkannya juga):

session_id exec_context_id wait_duration_ms wait_type blocking_session_id resource_description database_id
56 0 1 CXPACKET NULL exchangeEvent 13
56 1 1 CXPACKET 56 exchangeEvent 13
56 3 1 CXPACKET 56 exchangeEvent 13
56 4 1 CXPACKET 56 exchangeEvent 13
56 5 1 CXPACKET 56 exchangeEvent 13
56 6 1 CXPACKET 56 exchangeEvent 13
56 7 1 CXPACKET 56 exchangeEvent 13

Hasil yang menunjukkan aksi paralelisme miring

Utas kontrol adalah yang memiliki exec_context_id disetel ke 0. Utas paralel lainnya adalah yang memiliki exec_context_id lebih tinggi dari 0, dan semuanya menunjukkan CXPACKET menunggu selain dari satu (perhatikan bahwa exec_context_id = 2 hilang dari daftar). Anda akan melihat bahwa mereka semua mencantumkan session_id mereka sendiri sebagai salah satu yang memblokir mereka, dan itu benar karena semua utas menunggu utas lain dari session_id mereka sendiri untuk menyelesaikan. database_id adalah database yang konteksnya kueri dijalankan, belum tentu database tempat masalahnya, tetapi biasanya demikian, kecuali jika kueri menggunakan penamaan tiga bagian untuk dieksekusi di database yang berbeda.

Melihat Masalah Estimasi Kardinalitas

Dengan query_plan kolom di output kueri (yang saya hapus untuk kejelasan), Anda dapat mengkliknya untuk membuka rencana grafis dan kemudian klik kanan dan pilih Lihat dengan SQL Sentry Plan Explorer. Ini menunjukkan seperti di bawah ini:

Saya dapat langsung melihat bahwa ada masalah perkiraan kardinalitas, karena Baris Aktual untuk Pemindaian Indeks Berkelompok hanya 2.048, dibandingkan dengan 10.000.000 Baris (Perkiraan).

Jika saya menggulir, saya dapat melihat distribusi baris melintasi utas paralel yang digunakan:

Lihatlah, hanya satu utas yang melakukan pekerjaan apa pun selama bagian paralel dari rencana – utas yang tidak muncul di sys.dm_os_waiting_tasks keluaran di atas.

Dalam hal ini, perbaikannya adalah memperbarui statistik untuk tabel.

Dalam contoh buatan saya yang tidak akan berfungsi, karena belum ada modifikasi pada tabel, jadi saya akan menjalankan kembali skrip penyiapan, meninggalkan Statistik PEMBARUAN penyataan.

Rencana kueri kemudian menjadi:

Di mana tidak ada masalah kardinalitas dan juga tidak ada paralelisme – masalah terpecahkan!

Ringkasan

Jika Anda melihat CXPACKET menunggu terjadi, mudah untuk memeriksa paralelisme miring, menggunakan metode yang dijelaskan di atas. Semua kasus yang saya lihat disebabkan oleh masalah estimasi kardinalitas dari satu jenis atau lainnya, dan seringkali itu hanya kasus memperbarui statistik.

Sejauh menyangkut statistik tunggu umum, Anda dapat menemukan informasi lebih lanjut tentang menggunakannya untuk pemecahan masalah kinerja di:

  • Seri posting blog SQLskills saya, dimulai dengan statistik Tunggu, atau tolong beri tahu saya di bagian mana yang sakit
  • Perpustakaan Jenis Tunggu dan Kelas Latch Saya di sini
  • Kursus pelatihan online Pluralsight saya SQL Server:Pemecahan Masalah Kinerja Menggunakan Statistik Tunggu
  • Pengawal SQL

Sampai jumpa lagi, selamat memecahkan masalah!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Indeks Hilang di MS SQL atau Optimasi dalam waktu singkat

  2. Pertandingan Terdekat, Bagian 1

  3. Efek Samping yang Tidak Diinginkan – Sesi Tidur Memegang Kunci

  4. Bug Tampilan Terindeks dengan Agregat Skalar

  5. Pesanan Bersyarat Oleh