大規模なデータベースのフィールドでデータ クレンジングを実行しようとしています。必要に応じて、置換された単語、マクロを含む参照テーブルがあります。これらの変更を、可能な限り最も効率的な方法で、数百万行を含むテーブルに適用したいと考えています。そうは言っても、プロセスを視覚化できるように、以下にダミーデータをいくつか提供しましょう。
Street_Addresses テーブル:
Street_Name | Expanded_Name
------------------+--------------
100 Main St Ste 5 | NULL
25 10th Ave Apt 2 | NULL
75 Bridge Rd | NULL
Word_Substitutions テーブル:
Word | Replacement
-----+------------
St | Street
Ave | Avenue
Rd | Road
Ste | Suite
Apt | Apartment
したがって、更新後の最終結果は次のようになります。
Street_Name | Expanded_Name
------------------+--------------
100 Main St Ste 5 | 100 Main Street Suite 5
25 10th Ave Apt 2 | 25 10th Avenue Apartment 2
75 Bridge Rd | 75 Bridge Road
ここでの課題は、実行する必要がある膨大な数の置換であり、実際には単一の値に対して複数の置換が行われます。頭に浮かんだ最初の考えは、スカラー関数を使用してこのロジックをカプセル化することでした。しかし、ご想像のとおり、これは何百万行にも及ぶパフォーマンスではありません。
CREATE FUNCTION Substitute_Words (@Text varchar(MAX))
RETURNS varchar(MAX) AS
BEGIN
SELECT @Text = REPLACE(' ' + @Text + ' ', ' ' + Word + ' ',
' ' + Replacement + ' ') FROM Word_Substitutions
RETURN LTRIM(RTRIM(@Text))
END
代わりにセットベースの操作を検討することにし、次のことを思いつきました。
WHILE (1 = 1)
BEGIN
UPDATE A SET Expanded_Name = LTRIM(RTRIM(REPLACE(
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ',
' ' + W.Word + ' ', ' ' + W.Replacement + ' ')))
FROM Street_Addresses AS A
CROSS APPLY (SELECT TOP 1 Word, Replacement
FROM Word_Substitutions WHERE CHARINDEX(' ' + Word + ' ',
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ') > 0) AS W
IF (@@ROWCOUNT = 0)
BREAK
END
現在、これには実際のデータセットに基づいて約 2 時間かかります。可能であればそれを減らしたいと考えています。最適化の提案はありますか?
アップデート:
代わりに内部結合を使用するだけで、実行時間を約 5 分に短縮できました。最初は、複数の行を返す内部結合で update を使用するとうまくいかないと思っていました。更新は引き続き機能するように見えますが、ソース行は複数ではなく単一の更新を取得します。どうやら SQL Server は、更新のためにランダムな結果行を選択し、他の行を破棄します。
WHILE (1 = 1)
BEGIN
UPDATE A SET Expanded_Name = LTRIM(RTRIM(REPLACE(
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ',
' ' + W.Word + ' ', ' ' + W.Replacement + ' ')))
FROM Street_Addresses AS A
INNER JOIN Word_Substitutions AS W ON CHARINDEX(' ' + W.Word + ' ',
' ' + ISNULL(A.Expanded_Name, A.Street_Name) + ' ') > 0
IF (@@ROWCOUNT = 0)
BREAK
END