2009-03-03 15 views
18

Ich möchte auf die bestmögliche Weise zu Tabellen wechseln.
Ich habe eine IpToCountry-Tabelle, und ich erstellen eine neue auf einer wöchentlichen Basis nach einer externen CSV-Datei, die ich importiere.Tauschen von ms-sql-Tabellen

Der schnellste Weg, die ich gefunden habe den Schalter machen tat folgendes:

sp_rename IpToCountry IpToCountryOld 
go 
sp_rename IpToCountryNew IpToCountry 
go 

Das Problem dabei ist, dass der Tisch zwischen könnte noch zugegriffen in.
Wie gehe ich dieses Problem in SQL an?
In Betracht gezogen mit sp_getapplock und sp_releaseapplock, aber ich möchte das Lesen von der Tabellenfunktion so schnell wie möglich zu halten.

+1

ich SQL Server 2000 verwendet, ist die IpToCountryOld irrelevant und tatsächlich abgeschnitten worden sein könnte und fallen gelassen. Ich umbenenne, weil es schneller ist, dann lösche ich die alte Tabelle ... –

Antwort

16

Vorausgesetzt, dass Sie nicht in der vorhandenen Tabelle aktualisieren/einfügen können, warum wickeln Sie nicht alle Zugriff auf die Tabelle mit einem view?

Zum Beispiel könnten Sie zunächst speichern Sie Ihre Daten in einer Tabelle namens IpToCountry20090303, und Ihre Sicht wäre so etwas wie dieses:

CREATE VIEW IpToCountry 
AS 
SELECT * FROM IpToCountry20090303 

Wenn die neuen Daten in kommt, können Sie erstellen und füllen die IpToCountry20090310 Tabelle. Sobald die Tabelle ausgefüllt ist nur Ihre Ansicht aktualisieren:

ALTER VIEW IpToCountry 
AS 
SELECT * FROM IpToCountry20090310 

Der Schalter wird vollständig atomar sein, ohne eine explizite Sperre oder Transaktionen zu erfordern. Sobald die Ansicht aktualisiert wurde, können Sie einfach die alte Tabelle löschen (oder behalten, wenn Sie möchten).

+0

Ist das wirklich so einfach? http://stackoverflow.com/questions/3716546/why-cant-sql-server-alter-a-view-in-a-stored-procedure – mg1075

0

Was passiert mit IpToCountryOld? Wirfst du es weg? In diesem Fall, warum nicht IpToCountry abschneiden und meine neuen Daten importieren.

Wenn Sie die Daten aufbewahren müssen, wie wäre es, das Ladedatum auf der Tabelle zu speichern und das "aktuelle" Ladedatum irgendwo in einer WHERE-Klausel zu speichern? Dann wechseln Sie das aktuelle Datum, wenn die Daten erfolgreich geladen wurden.

Sie sagen nicht, welche DB Sie verwenden, also weiß ich nicht, wie viel das ist, aber haben Sie irgendwelche gespeicherten Prozeduren, die auf die Tabelle verweisen? Seien Sie gewarnt, dass auf einigen Plattformen SPs mit internen Verweisen auf Tabellen kompiliert werden, die sich bei einer Umbenennung nicht ändern. Daher besteht das Risiko, dass SPs Ihre neuen Daten nicht ohne Neukompilierung übernehmen. Dasselbe gilt für Ansichten und gespeicherte analysierte Abfragen.

+0

Hallo Mike, Ich benutze SQL Server 2000. Grundsätzlich ist die alte Tabelle irrelevant. Der Datenimport dauert einige Sekunden (zu einer neuen Tabelle + Indizierung). Ich möchte die Daten durch den minimalen Systemschaden ersetzen ... –

0

Können Sie den Import in die eine Tabelle während der arbeitsfreien Zeit nicht durchführen?

Oder warum nicht einfach eine Datenaktualisierung durchführen, dh die vorhandenen Datensätze aktualisieren und neue Datensätze satzweise hinzufügen, während Sie die Daten importieren. Dadurch könnte die Tabelle live bleiben und die Gesamtwirkung des Hinzufügens und Löschens von vollständigen Tabellen reduzieren.

Wie ist die Struktur der zu importierenden Daten, Tabellendesign, Format, PK usw.? Daraus können wir Ihnen vielleicht eine bessere Antwort geben.

+0

Die Daten sind IP-Adressen (fromIp, toIp (zusammen sind sie die PK), Land, Region, Stadt). Da sich IP-Bereiche immer ändern, wird das Update mit Löschen und Einfügen die Hölle sein. Ich kann es außerhalb der Geschäftszeiten tun, aber der Austausch wird immer noch Ausfallzeiten verursachen. Ich versuche den empfohlenen Weg zu finden ... –

1

Eine andere Methode zum Implementieren dessen, was Sie erreichen möchten, wäre die Verwendung der Tabellenpartitionierung, eine Technik, die in der Enterprise Edition von SQL Server verfügbar ist.

Der Tabellenname kann gleich bleiben.Nachdem der Tabellenimport abgeschlossen ist, schalten Sie einfach die Partition mit Ihren alten Daten aus und schalten die neue Partition ein.

Das folgende Whitepaper enthält alle Informationen, die Sie benötigen, um zu beginnen.

http://msdn.microsoft.com/en-us/library/ms345146.aspx

Cheers, John

+0

Hallo John, das ist ein paar interessante Sachen. In SQL2000 bin ich zwar immer noch gezwungen, die Views-Partitionierung zu verwenden, aber das ist gut zu wissen. Ich habe etwas zu lesen zu tun :) –

1

Ich habe Probleme Partitionierungsfunktionen immer in großem Umfang zu arbeiten. CREATE und DROP PARTITION blockieren Operationen, und Sie haben wenig Kontrolle über das Blockieren. Wenn es keine Sperre erhalten kann, wird es mit dem Schweregrad 16 fehlschlagen und Ihre Verbindung beenden - was Sie nicht abfangen und ohne erneute Wiederherstellung wiederholen können die Verbindung. Aber es könnte für Sie gut funktionieren. Außerdem wird MSS Enterprise Edition benötigt, Sie können SE nicht verwenden - dies könnte für einige kleinere oder kostenintensivere Geschäfte zu viel sein.

Ich habe auch gefunden, dass die Sicht redef auf High-Scale (= Transaktionsvolumen + bloße Menge von konstant eingefügten Daten, in meinem Fall) auf sys Tabellen und Objekte, so dass diese Operationen können Deadlock Dinge wie Reindexierung und DTCCs - und in einem Fall speziell mit einem Benutzer in SSMS (aus allen Dingen), der versucht, Ansichten im Object Explorer zu durchsuchen (jemand muss diesen Leuten von READPAST erzählen). Auch hier kann Ihre Laufleistung variieren.

Im Gegensatz dazu arbeitet die sp_rename gut für mich in großem Maßstab: es gibt Ihnen die Verriegelungs Kontrolle über und den Umfang davon. Um das Blockierungsproblem vor dem Austausch zu lösen, versuchen Sie es wie unten gezeigt. Auf den ersten Blick scheint dies das gleiche Größenproblem bei hoher Lautstärke zu haben ... aber ich habe es in der Praxis nicht gesehen. Also, funktioniert für mich ... aber wieder sind alle Bedürfnisse und Erfahrungen unterschiedlich.

+0

Sie können das gleiche mit sp_getapplock und sp_releaseapplock obwohl, die OP nicht wollen – gbn

+0

@ gbn, ich glaube nicht, sp_getapplock funktioniert das gleiche wie dies. sp_getapplock verhindert zwei gleichzeitige Ausführungen eines Codeblocks, aber wenn nicht jeder Befehl, der * diese Daten * liest, auch die gleiche Sperre verwendet (wahrscheinlich im gemeinsam genutzten Modus), gibt es nichts, was die Ausführung der Lesevorgänge verhindert, wenn die erste Tabelle dies nicht tut existieren. Der Ressourcenname in sp_getapplock ist nur eine willkürliche Zeichenfolge, und wenn * all * Zugriff auf diese Tabelle nicht durch sp_getapplock gated ist, können schlimme Dinge passieren.Wenn Sie TABLOCKX auf der Tabelle selbst verwenden, können keine Lesevorgänge auftreten, und Sie müssen nichts anderes tun, um sie zu verhindern. – Glazed

+0

@BLowery, müssen Sie nicht auch HOLDLOCK angeben, um die exklusive Tabellensperre für die Dauer der Transaktionen zu halten? Andernfalls wird die Sperre nur für die Dauer der Anweisung beibehalten. Sie können auch eine Transaktionsisolationsstufe von SERIALIZABLE angeben, um eine HOLDLOCK für alle Befehle zu erzwingen. Oder hält die Tatsache, dass Sie den Wert einer Variablen zuweisen, automatisch die Sperre? Ich habe diese genaue Technik nie wirklich probiert. Normalerweise mache ich Dinge wie "DELETE FROM Table WITH (TABLOCKX, HOLDLOCK)" und befülle dann die Tabelle. Ich weiß, dass der HOLDLOCK dort benötigt wird. – Glazed

0

Gerade lief ein ähnliches Problem bei der Arbeit an einer Staging-Tabelle, die Skalierung mit richtigen Sperren hatte.

überall Tisch verwiesen wird, könnten Sie eine gespeicherte Prozedur für die Tabellennamen zu fragen nennen.

Die gespeicherte Prozedur würde erstellen optional die neue Tabelle (n) oder die alten Tabellen zurückkehren abhängig von den bereitgestellten Parametern.

+0

Es ist am besten, Quellcode zur Verfügung zu stellen, um Ihre Antworten zu veranschaulichen – Mike

Verwandte Themen