web-dev-qa-db-fra.com

Requête de serveur lié SQL très très lente

J'extrais une grande quantité de données via un serveur lié à partir de VIEWS. J'utilise SQL Server 2012 et le serveur lié est SQL Server 2008

Ma déclaration choisie est 

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

Je m'attends à 300K lignes pour près de 700 ID. avant, cela prenait quelques heures, mais maintenant, il faut plus de 20 heures !!

Pourriez-vous s'il vous plaît suggérer une solution alternative pour cette douleur ?? 

Merci beaucoup d'avance!

14
arm

Lorsque vous utilisez un nom en 4 parties tel que [server].db.dbo.table, en particulier dans une join, le tableau entier est souvent copié par le fil sur la machine locale, ce qui n'est évidemment pas idéal.

Une meilleure approche consiste à utiliser une variable OPENQUERY, gérée à la source (serveur lié).

Essayer:

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

Avec cette approche, le serveur lié renverra toutes les lignes pour date> x, puis le serveur local filtrera cela par ID dans votre table locale.

Bien sûr, l’indexation jouera toujours un facteur pour faire SELECT * FROM DB.TABLE.VIEW WHERE DATE>'2012-01-01.

Une autre approche, que j'utilise pour les grands sous-ensembles, consiste à transférer les identifiants locaux sur le serveur distant, puis à gérer tout cela à distance, par exemple:

    -- 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]

Si la vue locale est également grande, vous pouvez alors envisager d'exécuter une requête distante qui utilise une requête ouverte sur la machine locale (en supposant que la machine distante utilise le lien local).

-- 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]
28
Dave Cullum

D'autres ont déjà suggéré l'indexation. Donc je ne vais pas là-bas. suggérer une autre option, si vous pouviez changer cette requête interne

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

Pour une requête joined utilisant inner join puisque vous avez dit avoir plus de 700 éléments inlist. Essaie.

   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'
1
Rahul