Accéder à la limite d’insertion de transaction dans la firebase database

Y a-t-il une limite au nombre d’insertions que vous pouvez effectuer dans une transaction Access avant de devoir valider ou avant qu’Access / Jet renvoie une erreur?

J’exécute actuellement le code suivant dans l’espoir de déterminer quel est ce maximum.

OleDbConnection cn = new OleDbConnection( @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\temp\myAccessFile.accdb;Persist Security Info=False;"); try { cn.Open(); oleCommand = new OleDbCommand("BEGIN TRANSACTION", cn); oleCommand.ExecuteNonQuery(); oleCommand.CommandText = "insert into [table1] (name) values ('1000000000001000000000000010000000000000')"; for (i = 0; i < 25000000; i++) { oleCommand.ExecuteNonQuery(); } oleCommand.CommandText = "COMMIT"; oleCommand.ExecuteNonQuery(); } catch (Exception ex) { } finally { try { oleCommand.CommandText = "COMMIT"; oleCommand.ExecuteNonQuery(); } catch{} if (cn.State != ConnectionState.Closed) { cn.Close(); } } 

L’erreur que j’ai reçue sur une application de production lorsque j’ai atteint 2 333 920 insertions dans une transaction unique non validée était: “Le nombre de verrous de partage de fichiers est dépassé. Augmentez l’entrée de registre MaxLocksPerFile”. La désactivation des transactions a résolu ce problème.

Oui, il y a en fait une limite. Et vous l’avez atteint clairement. Selon la documentation de Microsoft :

L’erreur se produit si le nombre de verrous requirejs pour effectuer une transaction dépasse le nombre maximal de verrous par fichier.

À ce lien, il existe deux solutions de contournement. Le second est plus réaliste, il modifie temporairement le nombre maximal de verrous.

Je viens de créer et de valider avec succès une transaction de 5 000 000 insertions sur une table d’une firebase database .accdb Une différence importante est que je n’ai pas émis directement d’instructions BEGIN TRANSACTION et COMMIT , mais que j’ai utilisé un object OleDbTransaction :

 cmd.CommandText = @"INSERT INTO Companies (ID, CompanyName) VALUES (?, ?)"; cmd.Parameters.Add("?", OleDbType.Integer); cmd.Parameters.Add("?", OleDbType.VarWChar, 255); cmd.Prepare(); OleDbTransaction tran = con.BeginTransaction(); cmd.Transaction = tran; for (int i = 1; i <= 5000000; i++) { if ((i % 100) == 0) { Console.WriteLine(i.ToString()); } cmd.Parameters[0].Value = i; cmd.Parameters[1].Value = "Company" + i.ToString(); cmd.ExecuteNonQuery(); } tran.Commit(); 

Editer re: commentaires

Après avoir créé et .Rollback() avec succès une transaction de 10 000 000 insertions et vérifié que le .Rollback() fonctionnait réellement (bonne suggestion, neoistheone!), J'ai vérifié le IsolationLevel de la transaction. Le paramètre par défaut IsolationLevel pour le pilote ACE.OLEDB est apparemment ReadCommitted , ce qui, selon MSDN, signifie:

Les verrous partagés sont conservés pendant la lecture des données pour éviter les lectures modifiées, mais les données peuvent être modifiées avant la fin de la transaction, ce qui entraîne des lectures non répétables ou des données fantômes.

Wikipedia a une bonne description de ces différents "phénomènes de lecture" ici .

Peut-être que si je devais spécifier un niveau d'isolation plus ssortingct (comme Serializable ), je pourrais atteindre la limite de locking décrite dans la question, bien que, puisqu'il s'agit de toutes les opérations INSERT, le pilote ACE.OLEDB doit peut-être simplement "masquer" les insertions. connexions jusqu'à ce qu'ils sont engagés.

Edit re: performance

Puisqu'une raison assez courante pour encapsuler un grand nombre d'opérations INSERT dans une transaction est de les faire plus rapidement, j'ai testé un lot de 100 000 inserts avec et sans OleDbTransaction . (L'instruction préparée a été utilisée dans les deux cas.) Sans OleDbTransaction le traitement du lot a pris environ 36 secondes. L'activation de OleDbTransaction avec le niveau d'isolation par défaut ( ReadCommitted ) a réduit le temps écoulé à environ 23 secondes.