it-swarm.it

Prestazioni di SQL Server Linked Server: perché le query remote sono così costose?

Ho due server di database, collegati tramite server collegati. Entrambi sono database SQL Server 2008R2 e la connessione al server collegato viene stabilita tramite un normale link "SQL Server", utilizzando il contesto di sicurezza dell'account di accesso corrente. I server collegati sono entrambi nello stesso datacenter, quindi la connessione non dovrebbe essere un problema.

Uso la seguente query per verificare quali valori della colonna identifier sono disponibili in remoto, ma non localmente.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT DISTINCT
    identifier 
FROM LocalDb.schema.[TableName] 

Su entrambe le tabelle sono presenti indici non cluster sulla colonna identifier. A livello locale sono circa 2,6 milioni di righe, solo 54 in remoto. Tuttavia, quando si esamina il piano di query, il 70% dei tempi di esecuzione è dedicato all'esecuzione di query remote. Inoltre, quando si studia il piano di query completo, il numero di righe locali stimate è 1 invece di 2695380 (che è il numero di righe stimate quando si seleziona solo la query successiva a EXCEPT). Execution plan Quando si esegue questa query, ci vuole davvero molto tempo.

Mi chiedo: perché è questo? La stima è "appena" lontana o le query remote su server collegati sono davvero così costose?

15
vstrien

Il piano che hai al momento sembra il piano più ottimale per me.

Non sono d'accordo con l'affermazione nelle altre risposte che sta inviando le righe 2.6M al server remoto.

Il piano mi sembra come se per ognuna delle 54 righe restituite dalla query remota stia eseguendo una ricerca dell'indice nella tabella locale per determinare se è abbinata o meno. Questo è praticamente il piano ottimale.

Sostituire con un hash join o unire join sarebbe controproducente date le dimensioni della tabella e l'aggiunta di un intermedio #temp table aggiunge solo un passaggio aggiuntivo che non sembra darti alcun vantaggio.

10
Martin Smith

La connessione a una risorsa remota è costosa. Periodo.

Una delle operazioni più costose in qualsiasi ambiente di programmazione è network IO (sebbene disk IO tende a sminuirlo).

Questo si estende ai server collegati remoti. Il server che chiama il server collegato remoto deve prima stabilire una connessione, quindi è necessario eseguire una query sul server remoto, restituire i risultati e chiudere la connessione. Tutto ciò richiede tempo sulla rete.


Dovresti anche strutturare la tua query in modo tale da trasferire i dati minimi attraverso il filo. Non aspettarti che il DB si ottimizzi per te.

Se dovessi scrivere questa query, selezionerei i dati remoti in una variabile di tabella (o in una tabella temporanea) e quindi li utilizzerei insieme alla tabella locale. Ciò garantisce che lo faranno solo i dati che devono essere trasferiti.

La query che stai eseguendo può facilmente inviare 2.6M righe al server remoto per elaborare la clausola EXCEPT.

6
Oded

Non sono un esperto, ma se si utilizza Union, Except o Intersect, non è necessario utilizzare "Distinct". A seconda dei valori di LocalDb.schema. [TableName], è possibile migliorare le prestazioni della query.

SELECT 
    identifier 
FROM LinkedServer.RemoteDb.schema.[TableName]

EXCEPT

SELECT 
    identifier 
FROM LocalDb.schema.[TableName]
1
joakon

Oded ha ragione, il problema delle prestazioni è causato dall'invio delle righe 2.6M al server remoto.

Per risolvere questo problema, puoi forzare l'invio dei dati remoti (54 righe) utilizzando una tabella temporanea o in memoria.

tilizzando una tabella temporanea

SELECT  identifier 
INTO    #TableName
FROM    LinkedServer.RemoteDb.schema.[TableName]

SELECT  identifier
FROM    #TableName
EXCEPT
SELECT  DISTINCT identifier 
FROM    LocalDb.schema.[TableName] 

DROP    #TableName
0

Penso che sia meglio replicare la tabella remota sul server da cui si esegue la query e quindi eseguire tutto il proprio SQL localmente.

0
Alen