web-dev-qa-db-fra.com

SQL Server: performances Insérer dans vs sélectionner dans

J'entends des choses différentes de la part de collègues/chercheurs. Quelles sont les bonnes lignes directrices en matière de performances, Select Into vs Insert into lors de la création d'une table temporaire? Je sais que la différence est minime pour les petites tables.

Par exemple: le tableau comporte 20 colonnes, 50 millions de lignes.

J'ai eu un état DBA, l'insertion dans est plus rapide, car le compilateur/analyseur n'a pas besoin de trouver les types de données de colonne à la volée. D'autres déclarant sélectionner dans est plus rapide. Nous avons effectué des tests de performances, et il semble que la sélection soit légèrement plus rapide.

Quels sont les bons principes pour déterminer lequel est le plus rapide et pourquoi? Je pense que Microsoft optimiserait pour faire de l'insertion dans, tout aussi rapide, pour une programmation minutieuse.

L'article stipule ce qui suit.

Performances SQL Server de SELECT INTO vs INSERT INTO pour les tables temporaires

La commande INSERT ... INTO réutilisera les pages de données créées dans le cache pour les opérations d'insertion/mise à jour/suppression. Il tronquera également la table lorsqu'elle sera supprimée. La commande SELECT ... INTO créera de nouvelles pages pour la création de tables similaires aux tables normales et les supprimera physiquement lorsque la table temporaire sera supprimée.

La question est, pourquoi Microsoft n'optimiserait-il pas pour rendre l'insertion aussi rapide que la sélection?

Nous avons plus de 500 procédures stockées à écrire pour l'entrepôt de données et nous avons besoin de bonnes directives pour l'utilisation temporaire.

Cet article ne se concentre pas vraiment sur les performances et les raisons:

INSERER DANS vs CHOISIR DANS

La personne dans l'article a mentionné un bon point:

c'est principalement parce que SQL Server sait qu'il n'y a pas de conflit pour la table de destination. La performance pour l'insertion dans #temp avec (tablock) select * from .. est à peu près la même que la performance pour select * into #temp from

2
user172193

Vous avez cité deux articles différents qui discutent de deux choses différentes.

Le premier article compare insert..select Avec select into Pour les tables temporaires , et le second compare ces deux en général .

En général, insert..select Est plus lent car il s'agit d'une opération entièrement enregistrée. select into Est enregistré de façon minimale dans les modèles de récupération simpleet bulk logged.

Le dernier commentaire que vous avez cité concerne insert into with(tablock), cette with(tablock) peut rendre insert into Connecté de façon minimale sous certaines conditions supplémentaires: il doit s'agir d'un segment de mémoire et ne pas avoir d'index.

Vous pouvez trouver le guide complet ici: The Data Loading Performance Guide

Il peut être résumé dans ce tableau:

enter image description here

Notez les mises à jour pour SQL Server 2016 et versions ultérieures SQL Server 2016, journalisation minimale et impact de la taille du lot dans les opérations de chargement en masse par Parik Savjani (un responsable de programme principal avec l'équipe Microsoft SQL Server Tiger). Le tableau mis à jour est:

updated chart for SQL Server 2016 onward

Concernant le premier article. Il examine le cas particulier des tables temporaires .

La base de données tempdb est spéciale car elle se trouve toujours dans le modèle de récupération simple et parce que la connexion à tempdb est différente. À chaque redémarrage du serveur, tempdb est recréé, cela signifie qu'aucune récupération brutale n'est effectuée pour tempdb, et cela signifie que la connexion à tempdb ne nécessite aucune image "après" de la modification données, seule l'image "avant" pour pouvoir faire un retour en arrière en cas de besoin. Cela conduit au fait que insert into..select Est également connecté de manière minimale tempdb même sans tablock indice (dans le cas d'un heap qui a été discuté dans le premier article ).

Conclusion "select into Vs insert..select Sous l'aspect journalisation":

Dans le cas d'un heap, insert into..select Fonctionne de la même manière que select into Dans le cas de tables temporaires, et est en général plus lent lorsque tablock hint n'est pas utilisé.

Le deuxième aspect est la possibilité d'exécution parallèle.

Select into Peut être exécuté en parallèle à partir de SQL Server 2014, et le parallèle insert...select A été implémenté pour la première fois dans SQL Server 2016.

Je n'ai reproduit aucune différence de performances entre select into Et insert into ..select Pour les tables temporaires sur SQL Server 2012, toutes exécutées en série.

2
sepupic

Quels sont les bons principes pour déterminer lequel est le plus rapide et pourquoi? Je pense que Microsoft optimiserait pour faire de l'insertion dans, tout aussi rapide, pour une programmation minutieuse.

Les principes que j'essaie de suivre en analysant quelque chose comme cette question sont:

  1. Évitez de faire des hypothèses inutiles.
  2. Lisez la documentation officielle.
  3. Testez la charge de travail. La quantité de tests dépend de la vitesse à laquelle j'ai besoin du code.

Je connais deux documents qui répondent à votre question. Le premier est un article de blog disant que SELECT INTO pour les tables temporaires a un comportement différent pour les écritures désirées à partir de SQL Server 2014. C'est par conception. Je ne pense donc pas qu'il soit correct de dire que la différence est minime pour les petites tables. Si quoi que ce soit, l'optimisation décrite dans le billet de blog semble conçue pour les petites tables:

Le changement dans SQL Server 2014 est de réduire le besoin de vider ces pages, aussi rapidement, dans les fichiers de données TEMPDB. Lorsque vous effectuez une sélection dans… #tmp… ou créez un index WITH SORT IN TEMPDB, SQL Server reconnaît maintenant que cela peut être une opération de courte durée. Les pages associées à une telle opération peuvent être créées, chargées, interrogées et publiées dans une très petite fenêtre de temps.

Par exemple: vous pourriez avoir une procédure stockée qui s'exécute en 8 ms. Dans cette procédure stockée, vous sélectionnez dans… #tmp… puis utilisez le #tmp et déposez-le à la fin de la procédure stockée.

Avant la modification de SQL Server 2014, la sélection dans peut avoir écrit toutes les pages accumulées sur le disque. Le comportement d'écriture rapide de SQL Server 2014 n'oblige plus ces pages à disque aussi rapidement que les versions précédentes. Ce comportement permet aux pages d'être stockées dans RAM (pool de tampons), interrogées et la table supprimée (supprimée du pool de tampons et renvoyée à la liste libre) sans jamais aller sur disque car la mémoire est longue En évitant autant que possible les E/S physiques, les performances de TEMPDB augmentent considérablement le fonctionnement en bloc et réduisent également l'impact sur les ressources du chemin d'E/S.

Le deuxième document explique cet insert parallèle dans les tables temporaires avec INSERT INTO ... SELECT est disponible sans indice TABLOCK dans SQL Server 2016 mais nécessite un indice TABLOCK dans SP1 et dans les versions futures.

Le problème est d'abord résolu dans SQL Server 2016 Service Pack 1. Après avoir appliqué SQL Server 2016 SP1, les INSERTS parallèles dans INSERT..SELECT aux tables temporaires locales sont désactivés par défaut, ce qui réduit les conflits sur la page PFS et améliore les performances globales pour la charge de travail simultanée. Si des INSERT parallèles aux tables temporaires locales sont souhaités, les utilisateurs doivent utiliser l'indication TABLOCK lors de l'insertion dans la table temporaire locale.

Pour en revenir à votre déclaration d'origine, vous ne pouvez pas déduire logiquement lequel des deux sera le plus rapide. Ce qui est plus rapide dépend de la façon dont Microsoft a conçu le logiciel et des caractéristiques de votre charge de travail. Il n'est tout simplement pas utile de deviner le temps nécessaire pour créer les définitions de colonne. Les tests sont utiles. Si vos tests suggèrent que SELECT INTO est plus rapide que cela. Pour ce que ça vaut, je travaille également sur le chargement de l'entrepôt de données avec un œil attentif sur les performances et je n'ai pas vu la différence entre les deux approches être quelque chose qui mérite d'être inquiété.

4
Joe Obbish

Chaque valeur traitée par SQL Server a un type de données. Les résultats d'un SELECT sont tous saisis. Ainsi, un SELECT..INTO n'a pas à déduire des types de données à la volée - ils sont définis par le SELECT.

En revanche, avec INSERT..SELECT, les colonnes source et destination peuvent être de types différents mais compatibles. Il y aura alors une contrainte de type implicite, qui consommera des cycles CPU. Je ne saurais dire si la différence de temps d'exécution peut être mesurée.

1
Michael Green