2016-07-21 10 views
1

Ich habe eine große Tabelle, die ich aktualisieren muss. Es wird durch das folgende Beispiel definiert (aber mir ist wirklich massiv 1 M + Reihen und Spalten) ...Optimierung einer rekursiven SQL-Abfrage

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); 

ich die WD Spalten dieser Datensätze aktualisieren müssen, die null WD Werte haben WD Wert entsprechen der erste Eintrag, wenn sie von [MRN] und [EPI] bestellt wurden. Die erforderliche Ausgabe wäre zum Beispiel:

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 

Mit den bearbeiteten Datensätzen am unteren Rand. Das ist was ich will. Allerdings ist diese Methode SLLLLOOOOWWW ... Sehr langsam, und aus gutem Grund bin ich über das gesamte Set Looping. Meine Fragen haben die Zieltabelle bereits indiziert:

  1. Wie kann ich diese Abfrage/Operation optimieren?
  2. Brauche ich hier sogar Rekursion?

Hier ist die gesamte Abfrage Testset jemanden zu helfen, die bereit ist, zu helfen:

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 

Vielen Dank für Ihre Zeit.

+0

Warum verwenden Sie eine Schleife mit dynamischen SQL für ein Update? Dies könnte als eine einzige Update-Anweisung ohne dynamisches SQL oder Looping umgeschrieben werden. –

+0

Weil ich rosten wie die Hölle und kämpfte um zu sehen, wie ich den ersten Datensatz eines Stapels erhalten konnte, um die gleiche Tabelle ohne Rekursion zu aktualisieren. Jede Hilfe würde sehr erhalten werden. – MoonKnight

+0

Ich folge nicht ganz der Logik dessen, was Sie hier erreichen wollen. Können Sie die Geschäftsregeln erklären? –

Antwort

0

ich verbessern Ich denke, ich verstehe was du bist versuchen zu tun. Es würde erheblich helfen, wenn Sie das, was Sie erwarten, als gewünschte Ausgabe veröffentlichen, so dass ich bestätigen konnte. Aber mit den Regeln und Daten sollte dies funktionieren.

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

Wird für einen großen Tisch umständlich sein. – NEER

0

Noch bin ich nicht klar über Ihre Abfrage. Wenn Sie jedoch die gleiche Abfrage verwenden möchten, können Sie folgende Verbesserungen in Betracht ziehen.

1) Warum machst du die Datenkonvertierung nach Varchar. Die Konvertierung erfolgt an 2 Stellen und, wenn es entfernt wird, verbessert es die Leistung. (Hope Konvertierung ist nicht erforderlich)

2) Die Indizes - Wie Sie filtern basierend auf 'MRN' und 'EPI', wenn Sie haben 2-Indizes für jede Filterung als

i) CREATE INDEX index_name ON table_name (MRN)

ii) CREATE INDEX index_name ON table_name (MRN, EPI)

, die auch Ihre Leistung

+1

Aber Indexierung ist hier nicht das Problem. Die eigentliche Leistungssenke ist der Cursor. –

Verwandte Themen