2012-05-22 19 views
29

He estado leyendo detenidamente diferentes prácticas recomendadas para bases de datos y para SQLite específicamente. Mientras leía, descubrí que estaba haciendo muchas cosas que no debería estar haciendo y, al intentar solucionar estos problemas, me confundí al pensar en algunos de los detalles más finos del uso de SQLite con su implementación de ADO.Conglomerado de conexiones SQLite/C# y confusión de sentencias preparadas

Mi confusión proviene específicamente de las declaraciones preparadas y la agrupación de conexiones.

Al leer http://msdn.microsoft.com/en-us/library/ms971481.aspx encontré que las conexiones solo deberían abrirse para una transacción. Una vez que se completa la transacción, la conexión debe cerrarse. No tengo una idea clara de por qué este es el caso, pero he estado trabajando en la suposición de que el autor sabe mejor que yo. Entiendo que cuando se cierra una conexión no significa que realmente estado cerrado Simplemente significa que ha sido devuelto a la piscina.

Ahora, para mejorar mis consultas e inserciones, leí sobre el uso de declaraciones preparadas. In SQLite, do prepared statements really improve performance? y http://petesbloggerama.blogspot.com/2007/02/sqlite-adonet-prepared-statements.html ambos parecían indicar que al ejecutar una consulta que se hará varias veces, las declaraciones preparadas son el camino a seguir. También he leído que una declaración preparada es específica para una conexión y que una vez que se cierra la conexión, la declaración preparada se pierde.

Mi confusión es esta. Si abro y cierro mi conexión (lo que puede o no significa que la conexión se cierre debido al grupo de subprocesos), ¿qué tanto uso obtengo de una declaración preparada? Puedo entender que si tengo 1000 objetos, necesito guardar en una sola transacción que la declaración preparada puede ayudar mucho. Sin embargo, no creo que vea un beneficio al guardar un solo objeto en una transacción porque una vez que cierro la conexión, la declaración preparada que se generó a partir del primer objeto ahora se pierde. ¿Es esta una afirmación verdadera?

Mi confusión se ve favorecida por el hecho de que creo que una declaración preparada está vinculada al alcance de mi objeto SQLiteCommand.

Si creo un SQLiteCommand que representa una consulta que ejecutaré a menudo, ¿debo mantener ese SQLiteCommand en memoria para que la declaración preparada permanezca activa?

Si creo un nuevo SQLiteCommand con la misma instrucción SQLite, ¿reconoce que el nuevo SQLiteCommand es el mismo que el anterior y, por lo tanto, tiene una declaración preparada que se puede usar?

Si guardo un SQLiteCommand en la memoria y cambio sus parámetros y conexión cuando abro y cierro la conexión para diferentes transacciones, ¿estoy esencialmente manteniendo viva una declaración preparada entre diferentes conexiones?

Probablemente estoy pensando demasiado en este punto, pero espero que pueda ayudarme a entender mejor cómo interactúan estas cosas para que pueda obtener el mayor beneficio de ellas.

+2

No estoy muy familiarizado con SQLite, pero con respecto a por qué uno debe cerrar las conexiones lo antes posible, estuvo cerca de responderlo usted mismo: la conexión física subyacente no está cerrada, simplemente devuelve la conexión al grupo. La implicación es que puede ser utilizado por otros hilos. Claramente, si se aferra a una conexión pero no la usa, eso limitará la máxima utilización posible. (Igualmente claro: si estás en un contexto de subproceso único, la agrupación de conexiones no tiene mucho sentido, aunque es poco probable que te haga mucho daño). –

Respuesta

0

No detecté exactamente cuál es el problema central, pero si el problema es cómo insertar declaraciones de inserción masiva en una transacción en tan poco tiempo.

Aquí es una clase de ayuda he encontrado anteriormente que podría ayudarle a:

SQLiteBulkInsertHelper.cs

Usted puede utilizar de esta manera:

SQLiteBulkInsertHelper ContactBlk = new SQLiteBulkInsertHelper("<SQLiteConnection>","<Table Name>"); 
ContactBlk.AllowBulkInsert = true; 
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.Int64); 
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.String); 
ContactBlk.Insert(new object[] {<First Column Value>,<Second Column Value>}); 
ContactBlk.Flush(); 

Darle una oportunidad si lo ve como una solución a su problema.

+0

Parece que el enlace que publicaste no funciona. (Chrome afirma que es un bucle de redirección sin fin) –

+0

, por supuesto, puede usar la línea de inserción en un bucle y llamar a las palabras clave de color para confirmar la transacción. El enlace de ayuda nuevamente: [SQLiteBulkInsertHelper.cs] (https://docs.google.com/open? id = 0B5-wcgU-Ku-eMDNlY1R3SzByV00) –

+0

OK gracias a que el enlace que publicaste en el comentario se ve bien También lo he solucionado en tu publicación. –

15

Es útil recordar que tanto la agrupación de conexiones como las declaraciones preparadas (compiladas) son solo herramientas que tienen sus límites y ningún enfoque puede ser igualmente adecuado para todas las situaciones posibles. Con esto en mente, recordemos cuando uno quiera usar la agrupación de conexiones y las declaraciones preparadas.

Razones posible el uso de Agrupación de conexiones

La agrupación de conexiones es útil cuando las conexiones son caros, por ejemplo:

  • Se necesita tiempo significativo para establecer una conexión (conexiones de red a un SQL Servidor o Oracle DB) y es beneficioso "cachear" las conexiones abiertas en un intento de mejorar el rendimiento del sistema.
  • Las conexiones son limitadas y compartidas dentro de una aplicación (conexiones de una aplicación web que atiende varias solicitudes concurrentes) o entre aplicaciones, por lo que deben liberarse lo antes posible para permitir que los demás clientes continúen.

Las posibles razones para usar sentencias preparadas

declaraciones preparadas son simplemente destinados a mejorar el rendimiento del reutilizables consultas al reducir el tiempo de análisis.

SQLite: ¿Cuál es la mejor opción?

La respuesta depende de los requisitos de su aplicación. Personalmente, no estoy seguro de si la agrupación de conexiones SQLite es necesariamente una buena opción. Si su aplicación es de subproceso único, sería mejor usar una única conexión permanente a la base de datos SQLite, que podría ser mucho más rápida que la agrupación y le permitiría también usar declaraciones preparadas. Esto es diferente de SQL Server donde la agrupación de conexiones es un valor predeterminado muy razonable.

Si el rendimiento importa, definitivamente debe perfilar la aplicación para ver si la agrupación de conexiones SQLite es beneficiosa para su escenario.

Preguntas Específicas

La mayoría de las respuestas se relacionan con el actual proveedor de System.Data.SQLitesource.

Si estoy abriendo y cerrando la conexión (que puede o no puede significar la conexión se cierra debido a la agrupación de hebras), entonces la cantidad de uso estoy realmente recibiendo de una declaración preparada?

En general, debe tratar una conexión que sale del grupo como nueva, es decir, no debe esperar obtener ningún beneficio de las declaraciones preparadas previamente. La declaración será "re-preparada" a menos que mantenga el comando y la conexión.

Sin embargo no creo que iba a ver un beneficio de ahorro de una sola objeto en una transacción porque una vez que cierro la conexión del declaración preparada que se generó desde el primer objeto es ahora perdido.¿Es esta una afirmación verdadera?

Esta es una declaración verdadera.

Si creo un SQLiteCommand que representa una consulta que seré ejecutar frecuencia necesito para mantener esa SQLiteCommand en la memoria para la declaración preparada para mantenerse activo?

Sí, lo necesitas conservar. SQLiteCommand contiene una referencia a la declaración preparada.

Si creo un nuevo SQLiteCommand con la misma declaración SQLite es que reconocido que el nuevo SQLiteCommand es el mismo que el anterior y por lo tanto tiene una declaración preparada que se puede utilizar?

No creo que sea compatible.

Si sigo un SQLiteCommand en la memoria y cambiar sus parámetros y conexión al abrir y cerrar la conexión para diferentes transacciones estoy manteniendo esencialmente una declaración preparada viva entre las diferentes conexiones?

Si cambia la conexión de SQLiteCommand, la declaración se "volverá a preparar".

+0

Una razón adicional muy importante para usar declaraciones preparadas, especialmente para inserciones y actualizaciones, es evitar ataques de inyección SQL. La instrucción preparada escapa correctamente del valor que se almacenará como está en la base de datos en todos los casos. –

Cuestiones relacionadas