2014-06-17 11 views
10

Ich extrahiere große Menge an Daten über den Verbindungsserver von VIEWS. Ich bin mit SQL Server 2012 und verknüpften Server ist SQL Server 2008SQL-Verbindungsserver Abfrage sehr sehr langsam

Meine select-Anweisung ist

SELECT * INTO MY_LOCAL_TABLE 
FROM 
( SELECT * FROM LINKEDSERVER.DB.TABLE.VIEW 
    WHERE DATE>'2012-01-01' AND ID IN (SELECT ID FROM MY_LOCAL_VIEW) 
) Q 

ich 300K Reihen erwarten für fast 700 + IDs. Früher dauerte es einige Stunden, aber jetzt dauert es mehr als 20 Stunden !!

Könnten Sie bitte irgendeine alternative Lösung für diese SCHMERZ vorschlagen ??

Vielen Dank im Voraus!

+0

Sind die Ansichten indiziert? wenn nicht, enthalten sie Unterabfragen? Wenn nicht, können Sie diesen Ansichten einen Index hinzufügen. – Pricey

+0

und rufen die Ansichten andere Ansichten, alawys eine Leistung no-no insbesondere über einen Verbindungsserver. – HLGEM

+0

ja die Ansichten sind richtig indiziert. Wenn ich OPENQUERY verwende, macht das einen Unterschied? oder SSIS-Paket? – arm

Antwort

1

Andere haben bereits über Indexierung vorgeschlagen. Also gehe ich nicht hin. eine andere Option vorschlagen, wenn Sie diese innere Abfrage

SELECT * FROM LINKEDSERVER.DB.TABLE.VIEW 
WHERE DATE>'2012-01-01' AND ID IN (SELECT ID FROM MY_LOCAL_VIEW) 

Zu einer joined Abfrage inner join Verwendung ändern könnte, da Sie 700+ InList Elemente mit dem. Versuche es.

SELECT lnv.* FROM LINKEDSERVER.DB.TABLE.VIEW lnv 
    inner join MY_LOCAL_VIEW mcv 
    on lnv.ID = mcv.ID 
    and lnv.DATE > '2012-01-01' 
+0

Cross-Server-Joins führen oft dazu, dass ganze Tabellen auf den lokalen Rechner kopiert werden. Dies sollte nur auf sehr kleinen Tabellen geschehen, die Sie sich leisten können. – JiggsJedi

+0

@JiggsJedi, das ist ziemlich wahr (wieder habe ich in meiner Antwort erwähnt .. es ist ein Vorschlag wert, einmal zu versuchen), aber wenn die verbundenen Tabellen nicht groß genug sind, wird dies die meiste Zeit Leistungssteigerung geben (nach meiner Beobachtung). – Rahul

24

Wenn Sie einen 4-teiligen Namen verwenden wie [server].db.dbo.table, vor allem in einem join, oft die gesamte Tabelle über den Draht auf den lokalen Computer kopiert, was natürlich nicht ideal ist.

Ein besserer Ansatz ist die Verwendung einer OPENQUERY - die an der Quelle (Verbindungsserver) behandelt wird.

Versuchen:

SELECT * 
FROM OPENQUERY([LINKEDSERVER], 'SELECT * FROM DB.TABLE.VIEW WHERE DATE>'2012-01-01') 
AND ID IN (SELECT ID FROM MY_LOCAL_VIEW) 

Mit diesem Ansatz der Verbindungsserver kehrt alle Zeilen für Datum> x, und dann der lokale Server filtert die von IDs in Ihrem lokalen Tabelle.

Natürlich spielt Indexierung immer noch eine Rolle, um SELECT * FROM DB.TABLE.VIEW WHERE DATE>'2012-01-01 zu tun.

Ein weiterer Ansatz, die ich auf große Untergruppen verwenden, ist es, die lokalen IDs auf dem Remote-Server zu entleeren, dann behandeln alle Ferne, wie zum Beispiel:

-- copy local table to linked server by executing remote query 
    DECLARE @SQL NVARCHAR(MAX) 
    SET @SQL = 'SELECT ID INTO db.dbo.tmpTable FROM [SERVER].DB.DBO.MY_LOCAL_VIEW' 
    EXEC(@SQL) AT [LINKEDSERVER] 

    -- index remote table?!? 
    DECLARE @SQL NVARCHAR(MAX) 
    SET @SQL = 'CREATE INDEX [IXTMP] ON db.dbo.tmpTable (ID)' 
    EXEC(@SQL) AT [LINKEDSERVER] 

    -- run query on local machine against both remote tables 
    SELECT * 
    -- INTO sometable 
    FROM OPENQUERY([LINKEDSERVER], 'SELECT * 
            FROM DB.TABLE.VIEW 
            WHERE DATE>''2012-01-01'' 
            AND ID IN (SELECT ID FROM db.dbo.tmpTable)') 

    -- now drop remote temp table of id's 
    DECLARE @SQL NVARCHAR(MAX) 
    SET @SQL = 'DROP TABLE db.dbo.tmpTable' 
    EXEC(@SQL) AT [LINKEDSERVER] 

Wenn die lokale Ansicht auch groß ist, dann Sie können in Betracht ziehen, eine Remote-Abfrage auszuführen, die eine OpenQuery zurück zum lokalen Rechner verwendet (vorausgesetzt, der Remote-Rechner hat den lokalen als Link).

-- copy local table to linked server by executing remote query 
DECLARE @SQL NVARCHAR(MAX) 
SET @SQL = 'SELECT ID INTO db.dbo.tmpTable FROM OPENQUERY([SERVER], ''SELECT ID FROM DB.DBO.MY_LOCAL_VIEW'')' 
EXEC(@SQL) AT [LINKEDSERVER] 
+0

+1 In der Tat ein guter Ansatz. Wusste darüber nicht (ich meine Openquery-Faktor). – Rahul

+0

Humm ... das scheint mir eine gute Idee zu sein. Ich bin nicht sicher, ob ich Zugriff auf temporäre Tabelle auf Verbindungsserver zu erstellen oder nicht habe, aber ich werde auf jeden Fall versuchen Sie Ihren Vorschlag als Verbindungsserver enthalten mehr als 50K IDs! Danke – arm

+0

Es ist möglich, die IDs in eine echte temporäre Tabelle (#table) zu setzen - jeder sollte Zugang haben, um sie zu erstellen, und alles auf einmal ausführen. Sie können immer auch eine Benutzertabelle in tempdb erstellen, die nicht in Ihrer Arbeitsdatenbank sein muss. – JiggsJedi