2016-07-21 15 views
1

更新が必要な大きなテーブルがあります。私はWDの値に一致するように、ヌルWD値を持っているそれらのレコードのWDの列を更新する必要が再帰SQLクエリの最適化

CREATE TABLE T 
    ([Errors] varchar(4), [MRN] int, [EPI] varchar(13), [WD] varchar(4)); 

INSERT INTO T 
    ([Errors], [MRN], [EPI], [WD]) 
VALUES 
(NULL, 107, 'IP00001070001', 'AMUM'), 
(NULL, 107, 'IP00001070001', 'AMUM'), 
(NULL, 107, 'IP00001070001', 'KNAP'), 
(NULL, 107, 'IP00001070002', 'KNAP'), 
(NULL, 107, 'IP00001070002', 'KNAP'), 
(NULL, 107, 'IP00001070002', 'KNAP'), 
(NULL, 107, 'IP00001070002', 'KNAP'), 
(NULL, 381, 'IP00003810001', 'EAUS'), 
(NULL, 381, 'IP00003810001', 'EAUS'), 
(NULL, 381, 'IP00003810003', 'DOCK'), 
(NULL, 381, 'IP00003810003', NULL), 
(NULL, 45, 'IP00000450001', 'ASES'), 
('__', 45, 'IP00000450002', NULL), 
('__', 381, 'IP00003810002', NULL); 

...次の例(しかし、私のは本当に大規模な1M +行と複数の列である)によって定義されます[MRN]と[EPI]によって発注された場合の最初のエントリ。たとえば、必要な出力は次のようになります。

Errors MRN EPI    WD 
NULL 107 IP00001070001 AMUM 
NULL 107 IP00001070001 AMUM 
NULL 107 IP00001070001 KNAP 
NULL 107 IP00001070002 KNAP 
NULL 107 IP00001070002 KNAP 
NULL 107 IP00001070002 KNAP 
NULL 107 IP00001070002 KNAP 
NULL 381 IP00003810001 EAUS 
NULL 381 IP00003810001 EAUS 
NULL 381 IP00003810003 EAUS 
NULL 381 IP00003810003 EAUS 
NULL 45 IP00000450001 ASES 
__  381 IP00003810003 EAUS 
__  45 IP00000450002 ASES 
__  381 IP00003810002 EAUS 

編集したレコードを下部に表示します。これは私が欲しいものです。しかし、このメソッドはSLLLLOOOOWWWです...非常に遅く、正当な理由で、私は全体のセットをループしています。私の質問はすでにターゲットテーブルのインデックスを作成しています:

  1. このクエリ/操作を最適化するにはどうすればよいですか?
  2. ここでも再帰が必要ですか?お時間を

    IF EXISTS (
        SELECT name 
        FROM sys.tables 
        WHERE name = N'T') 
    DROP TABLE [T] 
    GO 
    
    CREATE TABLE T 
        ([Errors] varchar(4), [MRN] int, [EPI] varchar(13), [WD] varchar(4)); 
    
    INSERT INTO T 
        ([Errors], [MRN], [EPI], [WD]) 
    VALUES 
        (NULL, 107, 'IP00001070001', 'AMUM'), 
        (NULL, 107, 'IP00001070001', 'AMUM'), 
        (NULL, 107, 'IP00001070001', 'KNAP'), 
        (NULL, 107, 'IP00001070002', 'KNAP'), 
        (NULL, 107, 'IP00001070002', 'KNAP'), 
        (NULL, 107, 'IP00001070002', 'KNAP'), 
        (NULL, 107, 'IP00001070002', 'KNAP'), 
        (NULL, 381, 'IP00003810001', 'EAUS'), 
        (NULL, 381, 'IP00003810001', 'EAUS'), 
        (NULL, 381, 'IP00003810003', 'DOCK'), 
        (NULL, 381, 'IP00003810003', 'DOCK'), 
        (NULL, 45, 'IP00000450001', 'ASES'), 
        ('__', 381, 'IP00003810003', NULL), 
        ('__', 45, 'IP00000450002', NULL), 
        ('__', 381, 'IP00003810002', NULL); 
    
    IF EXISTS (SELECT * 
          FROM sys.indexes 
          WHERE name='idxEETEST' AND object_id = OBJECT_ID('T')) 
    DROP INDEX [idxEETEST] ON [T]; 
    GO 
    
    CREATE NONCLUSTERED INDEX [idxEpiIPWardLoad] 
    ON [T] ([MRN], [EPI]) 
    GO 
    
    DECLARE @sql NVARCHAR(MAX) 
    DECLARE @mrn INT 
    DECLARE @epi NVARCHAR(16) 
    DECLARE @get_rec CURSOR 
    SET @get_rec = CURSOR FOR 
        SELECT MRN, EPI 
        FROM T 
        WHERE Errors IS NOT NULL 
    OPEN @get_rec 
    FETCH NEXT 
    FROM @get_rec INTO @mrn, @epi 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
        SET @sql = 
         'DECLARE @wd VARCHAR(4); ' + 
         'SELECT TOP 1 @wd = WD ' + 
         'FROM T ' + 
         'WHERE MRN = ' + Convert(VARCHAR, @mrn) + ';' + 
         'UPDATE T ' + 
         'SET WD = @wd ' + 
         'WHERE MRN = ' + Convert(VARCHAR, @mrn) + ' AND EPI = ''' + @epi + '''' 
        EXEC(@sql); 
    
        FETCH NEXT 
        FROM @get_rec INTO @mrn, @epi 
    END 
    CLOSE @get_rec 
    DEALLOCATE @get_rec 
    GO 
    
    IF EXISTS (SELECT * 
          FROM sys.indexes 
          WHERE name='idxEETEST' AND object_id = OBJECT_ID('T')) 
    DROP INDEX [idxEETEST] ON [T]; 
    GO 
    

    ありがとう:

はここで助けて喜んでいる人を支援するために設定し、全テストクエリです。

+0

なぜ動的SQLでループを使用して更新していますか?これは、動的SQLまたはループのない単一の更新文として書き直すことができます。 –

+0

私は地獄のように錆びていて、再帰せずに同じテーブルを更新するバッチの最初のレコードをどのように得ることができるか見て苦労していたからです。どんな助けも大いに受け取ります。 – MoonKnight

+0

私はあなたがここで成し遂げようとしていることの論理には全く従っていません。ビジネスルールを説明できますか? –

答えて

0

Iを改善

として、各フィルタリングI)TABLE_NAME ON INDEXのINDEX_NAMEをCREATEための2つの指標(MRN)

II)TABLE_NAMEのインデックスindex_nameのをCREATE(MRN、EPI)私はあなたが何であるかを理解すると思うやろうとしている。私が確認できるように、あなたが期待したものを投稿したら、それはかなり役に立ちます。しかし、ルールとデータが掲載されていれば、これはうまくいくはずです。

update t1 set WD = u.NewWD 
FROM T t1 
cross apply 
(
    select top 1 WD as NewWD 
    from T t2 
    where t2.MRN = t1.MRN 
    order by t2.EPI 
)u 
where t1.Errors is not null 
+0

大きなテーブルでは面倒です。 – NEER

0

まだ質問は不明です。しかし、同じクエリを使用したい場合は、以下の改善点を検討することができます。

1)なぜvarcharへのデータ変換を行っていますか? (希望の変換は不要です)

2)インデックス - 'MRN'と 'EPI'に基づいてフィルタリングしているので、また、あなたのパフォーマンス

+1

しかし、ここでは索引付けは問題ではありません。実際のパフォーマンスシンクはカーソルです。 –