Saya cukup yakin definisi tabel dekat dengan ini:
CREATE TABLE dbo.households
(
tempId integer NOT NULL,
n integer NOT NULL,
HHID integer IDENTITY NOT NULL,
CONSTRAINT [UQ dbo.households HHID]
UNIQUE NONCLUSTERED (HHID),
CONSTRAINT [PK dbo.households tempId, n]
PRIMARY KEY CLUSTERED (tempId, n)
);
CREATE TABLE dbo.persons
(
tempId integer NOT NULL,
sporder integer NOT NULL,
n integer NOT NULL,
PERID integer IDENTITY NOT NULL,
HHID integer NOT NULL,
CONSTRAINT [UQ dbo.persons HHID]
UNIQUE NONCLUSTERED (PERID),
CONSTRAINT [PK dbo.persons tempId, n, sporder]
PRIMARY KEY CLUSTERED (tempId, n, sporder)
);
Saya tidak memiliki statistik untuk tabel ini atau data Anda, tetapi yang berikut setidaknya akan mengatur kardinalitas tabel dengan benar (jumlah halaman adalah perkiraan):
UPDATE STATISTICS dbo.persons
WITH
ROWCOUNT = 5239842,
PAGECOUNT = 100000;
UPDATE STATISTICS dbo.households
WITH
ROWCOUNT = 1928783,
PAGECOUNT = 25000;
Analisis Rencana Kueri
Permintaan yang Anda miliki sekarang adalah:
UPDATE P
SET HHID = H.HHID
FROM dbo.households AS H
JOIN dbo.persons AS P
ON P.tempId = H.tempId
AND P.n = H.n;
Ini menghasilkan rencana yang agak tidak efisien:
Masalah utama dalam rencana ini adalah hash join dan sortir. Keduanya membutuhkan hibah memori (hash join perlu membangun tabel hash, dan sort membutuhkan ruang untuk menyimpan baris saat penyortiran berlangsung). Plan Explorer menunjukkan permintaan ini diberikan 765 MB:
Ini cukup banyak memori server yang didedikasikan untuk satu permintaan! Lebih penting lagi, pemberian memori ini diperbaiki sebelum eksekusi dimulai berdasarkan jumlah baris dan perkiraan ukuran.
Jika memori ternyata tidak mencukupi pada waktu eksekusi, setidaknya beberapa data untuk hash dan / atau pengurutan akan ditulis ke disk tempdb fisik . Ini dikenal sebagai 'tumpahan' dan ini bisa menjadi operasi yang sangat lambat. Anda dapat melacak tumpahan ini (dalam SQL Server 2008) menggunakan peristiwa Profiler Peringatan Hash dan Sortir Peringatan .
Perkiraan untuk input build tabel hash sangat baik:
Perkiraan untuk input sortir kurang akurat:
Anda harus menggunakan Profiler untuk memeriksa, tetapi saya curiga jenisnya akan tumpah ke tempdb dalam kasus ini. Mungkin juga tabel hash juga ikut tumpah, tapi itu kurang jelas.
Perhatikan bahwa memori yang dicadangkan untuk kueri ini dibagi antara tabel hash dan urutkan, karena mereka menjalankan secara bersamaan. Properti paket Fraksi Memori menunjukkan jumlah relatif dari hibah memori yang diharapkan akan digunakan oleh setiap operasi.
Mengapa Menyortir dan Hash?
Pengurutan ini diperkenalkan oleh pengoptimal kueri untuk memastikan bahwa baris tiba di operator Pembaruan Indeks Clustered dalam urutan kunci terkelompok. Ini mempromosikan akses berurutan ke tabel, yang seringkali jauh lebih efisien daripada akses acak.
Gabung hash adalah pilihan yang tidak terlalu jelas, karena inputnya berukuran sama (untuk perkiraan pertama). Hash join adalah yang terbaik di mana satu input (input yang membangun tabel hash) relatif kecil.
Dalam kasus ini, model penetapan biaya pengoptimal menentukan bahwa hash join adalah yang lebih murah dari tiga opsi (hash, merge, nested loop).
Meningkatkan Kinerja
Model biaya tidak selalu benar. Ini cenderung untuk memperkirakan biaya gabungan paralel, terutama karena jumlah utas meningkat. Kami dapat memaksa gabungan bergabung dengan petunjuk kueri:
UPDATE P
SET HHID = H.HHID
FROM dbo.households AS H
JOIN dbo.persons AS P
ON P.tempId = H.tempId
AND P.n = H.n
OPTION (MERGE JOIN);
Ini menghasilkan paket yang tidak membutuhkan banyak memori (karena menggabungkan gabungan tidak memerlukan tabel hash):
Urutan bermasalah masih ada, karena gabungan bergabung hanya mempertahankan urutan kunci gabungannya (tempId, n) tetapi kunci yang dikelompokkan adalah (tempId, n, sporder). Anda dapat menemukan rencana bergabung gabung melakukan tidak lebih baik dari rencana bergabung hash.
Nested Loops Bergabung
Kami juga dapat mencoba loop bersarang bergabung:
UPDATE P
SET HHID = H.HHID
FROM dbo.households AS H
JOIN dbo.persons AS P
ON P.tempId = H.tempId
AND P.n = H.n
OPTION (LOOP JOIN);
Rencana kueri ini adalah:
Rencana kueri ini dianggap yang terburuk oleh model penetapan biaya pengoptimal, tetapi memang memiliki beberapa fitur yang sangat diinginkan. Pertama, loop bersarang bergabung tidak memerlukan hibah memori. Kedua, ia bisa mempertahankan urutan kunci dari Persons
tabel sehingga pengurutan eksplisit tidak diperlukan. Anda mungkin menemukan bahwa rencana ini berkinerja relatif baik, bahkan mungkin cukup baik.
Loop Bersarang Paralel
Kelemahan besar dengan rencana loop bersarang adalah bahwa ia berjalan pada satu utas. Kemungkinan kueri ini mendapat manfaat dari paralelisme, tetapi pengoptimal memutuskan tidak ada keuntungan dalam melakukan itu di sini. Ini belum tentu benar juga. Sayangnya, tidak ada petunjuk kueri bawaan untuk mendapatkan paket paralel, tetapi ada cara tidak berdokumen:
UPDATE t1
SET t1.HHID = t2.HHID
FROM dbo.persons AS t1
INNER JOIN dbo.households AS t2
ON t1.tempId = t2.tempId AND t1.n = t2.n
OPTION (LOOP JOIN, QUERYTRACEON 8649);
Mengaktifkan jejak flag 8649 dengan QUERYTRACEON
petunjuk menghasilkan rencana ini:
Sekarang kami memiliki rencana yang menghindari penyortiran, tidak memerlukan memori tambahan untuk bergabung, dan menggunakan paralelisme secara efektif. Anda harus menemukan kueri ini berkinerja lebih baik daripada alternatifnya.
Informasi lebih lanjut tentang paralelisme dalam artikel saya Memaksa Rencana Eksekusi Paralel :