|
Publicité ' | |||||||||||||||||||||||
|
|
#1 |
|
Nouveau Membre du Club
![]() IED décisionnel Inscription : mai 2011 Messages : 33 ![]() |
Bonjour,
Je dois intégrer 45 Millions d'enregistrements dans une table d'une BDD Configuration : WINDOWS 2003 X64 SQL SERVER 2008 R2 18 G de ram (14G pour SQL SERVER) 4 Processeurs Voici la structure de la requête exécutée: INSERT INTO baseB.TableA (Champ1, Champ2, ....) SELECT Champ1, Champ2, .... FROM baseA.TableA Le traitement s'exécute correctement on peut voir les ligne se charger dans la table BaseB.TableA jusqu'a 42 Millions de lignes, après le nombre d'enregistrements redescend à 0 et nous avons l'erreur suivante: DESCRIPTION: Error: 1204, Severity: 19, State: 1 The SQL Server cannot obtain a LOCK resource at this time. Rerun your statement when there are fewer active users or ask the system administrator to check the SQL Server lock and memory configuration. Le probleme se reproduit à 9 millions de lignes sur un serveur plus "petit" 2G de ram 1 proc Windwos server 2003 32 sql server 2008 r2 test réaliser un select sur toute la table provoque l'erreur suivante: Une erreur s'est produite lors de l'exécution du lot. Message d'erreur*: Une exception de type 'System.OutOfMemoryException' a été levée. Comment peut-on empêcher ces problèmes ? Merci |
|
|
00
|
|
|
#2 | ||
![]() ![]() ![]() Nicolas SouquetAdministrateur de base de données Inscription : janvier 2005 Messages : 4 669 ![]() |
Bonjour,
C'est un problème d'escalade de verrous. Comme votre transaction est longue et que chaque ligne insérée / lue doit être verrouillée pour toute la durée de la transaction, un grand nombre de verrous doivent être gérés par SQL Server. Je ne me souviens plus des seuils exacts, mais quand SQL Server maintient environ 5,000 verrous de ligne (par exemple), il "escalade" et le remplace par un seul verrou de page, de façon à consommer moins de mémoire. La contrepartie est que la concurrence sur la table est moins élevée (on bloque plus "large"). Il en va ainsi de suite pour l'extent (groupe de 8 pages), puis la table (n'hésitez pas à me corriger si un verrou au niveau partition est pris, mais je ne crois pas que ce soit le cas). Chaque verrou coûte 96 octets de mémoire. La quantité maximale de mémoire allouée aux verrous est de 40% de la mémoire totale allouée à SQL Server. Donc moins votre serveur a de mémoire, plus vite vous obtenez le problème. Enfin un verrou ne peut pas être acquis dans certaines conditions si une autre transaction a démarré et lit les données que vous voulez lire également. La règle générale est : faites en sorte que vos transactions soient courtes. Ce qui se traduit pour votre cas par un insertion en lots de ligne : vous insérez, mettons, 1 million de lignes, puis encore un million, ... D'habitude je fais cela pour des UPDATE massifs, mais le principe reste le même : stockez dans une table séparée seulement la clé primaire de la table, en conjonction avec une colonne de type int auto-incrémentée (IDENTITY). Ensuite vous procédez par lot en faisant une jointure entre les la table qui subit le SELECT et cette table BETWEEN 1 AND 1,000,000, et vous incrémentez pour passer au lot suivant d'un million de lignes. Code :
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes. Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012 |
||
|
00
|
|
|
#3 | |||||
|
Membre chevronné
![]() ![]() Inscription : juillet 2006 Messages : 1 194 ![]() |
Je ne connais pas bien la version 2008 (et 2008 R2) mais, il me semble que vous pouvez définir le lock escalation table par table.
Alors peut-être pourriez-vous définir qu'un lock est pris sur toute la table Citation:
Code :
|
|||||
|
|
00
|
|
|
#4 |
|
Nouveau Membre du Club
![]() IED décisionnel Inscription : mai 2011 Messages : 33 ![]() |
Merci pour votre aide vous avez répondus à mes interrogations
|
|
|
00
|
|
|
#5 | ||
![]() ![]() ![]() Nicolas SouquetAdministrateur de base de données Inscription : janvier 2005 Messages : 4 669 ![]() |
Citation:
Le seul moyen de le forcer à le faire se fait au niveau de l'instance par le traceflag 1211, ou 1224 pour être moins brutal. Dans les deux cas, c'est dangereux. Citation:
La table que je donne est mono-colonne, et indexée en cluster ... @++
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes. Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012 |
||
|
00
|
|
|
#6 | |
|
Membre Expert
![]() |
Citation:
__________________
Prendre conscience, c'est transformer le voile qui recouvre la lumière en miroir. |
|
|
|
00
|
|
|
#7 | ||
|
Membre chevronné
![]() ![]() Inscription : juillet 2006 Messages : 1 194 ![]() |
Je ne suis pas d'accord.
J'ai fait quelques tests et la solution de Elsuket est moins rapide que la mienne, l'overhead causé par la population de la table cle_primaire est trop important. L'intérêt de sa solution est l'utilisation d'une clause WHERE avec des bornes (sans clé numérique, ce serait pê moins efficace) ce qui est bien plus rapide que la clause EXISTS (ou équivalent) que j'utilise (et indépendamment du fait d'être une auto-jointure). Mais, toujours dans le cas d'une clé numérique, il existe un moyen intéressant d'optimiser l'approche par bornes d'Elsuket (ps: attention, Elsuket inserait parfois 2 fois le même record). Voici mon code pour insérer des records par million (au singulier). Code :
![]() Sur ce, bien que ne l'ayant pas démonté, je me permet d'affirmer sur base de mes témoignages qu'aucune perte de performance pertinente était à noter lors de l'emploi d'une auto-jointure plutôt qu'une autre jointure conjugué à l'emploi d'un insert (témoignage valant pour SQL Server 2005). |
||
|
|
00
|
Copyright © 2000-2012 - www.developpez.com