Intinya : Menambahkan kriteria ke WHERE
klausa dan memecah kueri menjadi empat kueri terpisah, satu untuk setiap bidang memungkinkan server SQL untuk menyediakan rencana paralel dan membuat kueri berjalan 4X secepat yang dimilikinya tanpa pengujian tambahan dalam WHERE
klausa. Memisahkan kueri menjadi empat tanpa tes tidak berhasil. Juga tidak menambahkan tes tanpa memecah pertanyaan. Mengoptimalkan tes mengurangi total waktu berjalan menjadi 3 menit (dari aslinya 3 jam).
UDF asli saya memerlukan 3 jam 16 menit untuk memproses 1.174.731 baris, dengan 1.216 GB data nvarchar diuji. Menggunakan CLR yang disediakan oleh Martin Smith dalam jawabannya, rencana eksekusi masih tidak paralel dan tugasnya memakan waktu 3 jam dan 5 menit.
Setelah membaca bahwa WHERE
kriteria dapat membantu mendorong suatu UPDATE
paralel, saya melakukan hal berikut. Saya menambahkan fungsi ke modul CLR untuk melihat apakah bidang tersebut cocok dengan regex:
[SqlFunction(IsDeterministic = true,
IsPrecise = true,
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None)]
public static SqlBoolean CanReplaceMultiWord(SqlString inputString, SqlXml replacementSpec)
{
string s = replacementSpec.Value;
ReplaceSpecification rs;
if (!cachedSpecs.TryGetValue(s, out rs))
{
var doc = new XmlDocument();
doc.LoadXml(s);
rs = new ReplaceSpecification(doc);
cachedSpecs[s] = rs;
}
return rs.IsMatch(inputString.ToString());
}
dan, dalam internal class ReplaceSpecification
, saya menambahkan kode untuk menjalankan tes terhadap regex
internal bool IsMatch(string inputString)
{
if (Regex == null)
return false;
return Regex.IsMatch(inputString);
}
Jika semua bidang diuji dalam satu pernyataan, SQL server tidak memparalelkan pekerjaan
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X),
DE461 = dbo.ReplaceMultiWord(DE461, @X),
DE87 = dbo.ReplaceMultiWord(DE87, @X),
DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND (dbo.CanReplaceMultiWord(IndexedXml, @X) = 1
OR DE15 = dbo.ReplaceMultiWord(DE15, @X)
OR dbo.CanReplaceMultiWord(DE87, @X) = 1
OR dbo.CanReplaceMultiWord(DE15, @X) = 1);
Waktu untuk mengeksekusi lebih dari 4 1/2 jam dan masih berjalan. Rencana eksekusi:
Namun, jika bidang dipisahkan ke dalam pernyataan terpisah, rencana kerja paralel digunakan, dan penggunaan CPU saya beralih dari 12% dengan paket seri menjadi 100% dengan paket paralel (8 core).
UPDATE dbo.DeidentifiedTest
SET IndexedXml = dbo.ReplaceMultiWord(IndexedXml, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(IndexedXml, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE461 = dbo.ReplaceMultiWord(DE461, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE461, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE87 = dbo.ReplaceMultiWord(DE87, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE87, @X) = 1;
UPDATE dbo.DeidentifiedTest
SET DE15 = dbo.ReplaceMultiWord(DE15, @X)
WHERE InProcess = 1
AND dbo.CanReplaceMultiWord(DE15, @X) = 1;
Waktu untuk mengeksekusi 46 menit. Statistik baris menunjukkan bahwa sekitar 0,5% dari catatan memiliki setidaknya satu pertandingan regex. Rencana eksekusi:
Sekarang, hambatan utama tepat waktu adalah WHERE
klausa. Saya kemudian mengganti tes regex dalam WHERE
klausa dengan algoritma Aho-Corasick diimplementasikan sebagai CLR. Ini mengurangi total waktu menjadi 3 menit 6 detik.
Ini membutuhkan perubahan berikut. Memuat perakitan dan fungsi untuk algoritma Aho-Corasick. Ubah WHERE
klausa menjadi
WHERE InProcess = 1 AND dbo.ContainsWordsByObject(ISNULL(FieldBeingTestedGoesHere,'x'), @ac) = 1;
Dan tambahkan berikut ini sebelum yang pertama UPDATE
DECLARE @ac NVARCHAR(32);
SET @ac = dbo.CreateAhoCorasick(
(SELECT NAMES FROM dbo.NamesMultiWord FOR XML RAW, root('root')),
'en-us:i'
);
SELECT @var = REPLACE ... ORDER BY
konstruksi tidak dijamin untuk bekerja seperti yang Anda harapkan. Contoh Sambungkan item (lihat respons dari Microsoft). Jadi, beralih ke SQLCLR memiliki keuntungan tambahan untuk menjamin hasil yang benar, yang selalu menyenangkan.