Question

Je dois effectuer une mise à jour quotidienne d'un fichier très volumineux (300 millions d'enregistrements) et large TABLE1.Les données sources des mises à jour se trouvent dans une autre table UTABLE soit 10 % à 25 % des rangées de TABLE1 mais il est étroit.Les deux tableaux ont record_id comme clé primaire.

Actuellement, je recrée TABLE1 en utilisant l'approche suivante :

<!-- language: sql -->
    1) SELECT (required columns) INTO TMP_TABLE1 
    FROM TABLE1 T join UTABLE U on T.record_id=U.record_id  
    2) DROP TABLE TABLE1  
    3) sp_rename 'TMP_TABLE1', 'TABLE1'

Or cela prend près de 40 minutes sur mon serveur (60 Go de RAM pour SQL Server).Je souhaite obtenir un gain de performances de 50 % : quelles autres options puis-je essayer ?

  1. MERGE et UPDATE - quelque chose comme le code ci-dessous ne fonctionne plus rapidement que pour un très petit UTABLE table - en taille réelle, tout se bloque :

    <!-- language: SQL -->
    MERGE TABLE1 as target  
    USING UTABLE as source  
    ON target.record_id = source.record_id   
      WHEN MATCHED THEN   
        UPDATE SET Target.columns=source.columns
    
  2. J'ai entendu dire que je pouvais effectuer une MERGE par lots en utilisant ROWCOUNT - mais je ne pense pas que cela puisse être assez rapide pour une table de 300 millions de lignes.

  3. Des astuces de requête SQL qui peuvent être utiles ?

Était-ce utile?

La solution

En fait, j'ai découvert des recommandations générales pour de telles requêtes :L'idée d'utiliser SQL Merge ou Update est très intelligente, mais elle échoue lorsque nous devons mettre à jour de nombreux enregistrements (c'est-à-dire 75M) dans une grande et large table (c'est-à-dire 240M).

En regardant le plan de requête de la requête ci-dessous, nous pouvons dire que TABLE SCAN du TABLEAU1 et final MERGE prennent 90% du temps.

MERGE TABLE1 as Target  
USING UTABLE as source  
ON Target.record_id = source.record_id   
WHEN MATCHED AND (condition) THEN   
    UPDATE SET Target.columns=source.columns

Donc, pour utiliser MERGE, nous devons :

  1. Réduisez le nombre de lignes que nous devons mettre à jour et transmettez correctement ces informations à SQL Server.Cela peut être fait en faisant UTABLE plus petit ou en spécifiant des condition cela rétrécit la partie à fusionner.
  2. Assurez-vous que la partie à fusionner tient dans la mémoire, sinon la requête s'exécute beaucoup plus lentement.Fabrication TABLE1 deux fois moins, j'ai réduit mon temps réel de requête de 11 heures à 40 minutes.

Comme Mark l'a mentionné, vous pouvez utiliser UPDATE syntaxe et utilisation WHERE clause pour restreindre la partie à fusionner - cela donnera les mêmes résultats.Veuillez également éviter d'indexer TABLE1 car cela entraînera un travail supplémentaire pour reconstruire l'index pendant MERGE

Autres conseils

Tout d'abord, je découvrirais où se trouve votre goulot d'étranglement : votre processeur est-il bloqué ou inactif ?En d’autres termes : votre sous-système IO est-il capable de gérer la charge correctement ?

Recréer la table complète représente beaucoup de charge d'E/S, sans compter que cela prendra beaucoup d'espace pour stocker la table deux fois temporairement.

Avez-vous besoin d'effectuer une MERGE - d'après ce que je peux voir, une simple mise à jour devrait suffire.Exemple:

UPDATE
    TABLE1
SET
    ColumnX = UTABLE.ColumnX
    ...
FROM
    TABLE1
INNER JOIN
    UTABLE ON TABLE1.record_id = UTABLE.record_id

Vous pouvez regrouper les mises à jour à l'aide de ROWCOUNT, mais cela n'accélérera pas l'exécution, cela contribuera uniquement à réduire le verrouillage global.

Aussi : quel type d’index avez-vous sur la table ?Il peut être plus rapide de désactiver les index avant la mise à jour, puis de les reconstruire à partir de zéro par la suite (uniquement les index non clusterisés).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top