Advertencia: puede haber imprecisiones a continuación. He estado aprendiendo sobre muchas de estas cosas a medida que avanzo, así que tómalo con una pizca de sal. Esto es bastante largo, pero puedes leer los parámetros con los que estábamos jugando y luego saltar a la conclusión al final.
Hay varias capas en las que puede preocuparse por el rendimiento de escritura de SQLite:
Observamos los resaltados en negrita. Los parámetros particulares fueron
- Disco de caché de escritura. Los discos modernos tienen caché RAM que se utiliza para optimizar las escrituras del disco con respecto al disco giratorio. Con esto habilitado, los datos pueden escribirse en bloques desordenados, por lo que si ocurre un bloqueo, puede terminar con un archivo parcialmente escrito. Verifique la configuración con hdparm -W / dev / ... y configúrelo con hdparm -W1 / dev / ... (para encenderlo y -W0 para apagarlo).
- barrera = (0 | 1). Muchos comentarios en línea que dicen "si ejecuta con barrera = 0, entonces no tiene habilitado el almacenamiento en caché de escritura en disco". Puede encontrar un debate sobre las barreras en http://lwn.net/Articles/283161/
- datos = (diario | ordenado | reescritura). Consulte http://www.linuxtopia.org/HowToGuides/ext3JournalingFilesystem.html para obtener una descripción de estas opciones.
- commit = N. Le dice a ext3 que sincronice todos los datos y metadatos cada N segundos (predeterminado 5).
- Pragma SQLite sincrónico = ON | APAGADO. Cuando está activado, SQLite se asegurará de que una transacción se "escriba en el disco" antes de continuar. Desactivar esto esencialmente hace que las otras configuraciones sean irrelevantes.
- SQLite pragma cache_size. Controla la cantidad de memoria que SQLite usará para su caché en memoria. Intenté dos tamaños: uno en el que toda la base de datos cabría en la memoria caché y otra en la que la memoria caché era la mitad del tamaño máximo de la base de datos.
Lea más sobre las opciones de ext3 en la documentación de ext3 .
Realicé pruebas de rendimiento en varias combinaciones de estos parámetros. La ID es un número de escenario, mencionado a continuación.
Comencé ejecutando con la configuración predeterminada en mi máquina como escenario 1. El escenario 2 es lo que supongo que es el "más seguro", y luego probé varias combinaciones, según corresponda / solicitada. Esto es probablemente más fácil de entender con el mapa que terminé usando:
Escribí un script de prueba que ejecutaba muchas transacciones, con inserciones, actualizaciones y eliminaciones, todo en tablas con INTEGER, TEXT (con columna de identificación) o mixto. Ejecuté esto varias veces en cada una de las configuraciones anteriores:
Los dos escenarios inferiores son # 6 y # 17, que tienen "pragma synchronous = off", tan sorprendente que fueron los más rápidos. El siguiente grupo de tres son # 7, # 11 y # 19. Estos tres están resaltados en azul en el "mapa de configuración" anterior. Básicamente, la configuración es caché de escritura en disco activada, barrera = 0 y conjunto de datos en algo diferente a 'diario'. Cambiar la confirmación entre 5 segundos (# 7) y 60 segundos (# 11) parece hacer poca diferencia. En estas pruebas, no parecía haber mucha diferencia entre datos = ordenados y datos = reescritura, lo que me sorprendió.
La prueba de actualización mixta es el pico medio. Hay un grupo de escenarios que son claramente más lentos en esta prueba. Todos estos son con data = journal . De lo contrario, no hay mucho entre los otros escenarios.
Tuve otra prueba de tiempo, que hizo una mezcla más heterogénea de inserciones, actualizaciones y eliminaciones en las diferentes combinaciones de tipos. Estos tomaron mucho más tiempo, por lo que no lo incluí en el diagrama anterior:
Aquí puede ver que la configuración de reescritura (# 19) es un poco más lenta que las ordenadas (# 7 y # 11). Esperaba que la reescritura fuera un poco más rápida, pero tal vez depende de sus patrones de escritura, o tal vez todavía no he leído lo suficiente en ext3 :-)
Los diversos escenarios eran algo representativos de las operaciones realizadas por nuestra aplicación. Después de elegir una lista breve de escenarios, realizamos pruebas de tiempo con algunas de nuestras suites de pruebas automatizadas. Estaban en línea con los resultados anteriores.
Conclusión
- El parámetro commit parecía hacer poca diferencia, así que lo dejamos en 5s.
- Vamos con caché de escritura en disco, barrera = 0 , y datos = ordenados . Leí algunas cosas en línea que pensaban que esta era una mala configuración, y otras que parecían pensar que esto debería ser lo predeterminado en muchas situaciones. Supongo que lo más importante es que tome una decisión informada, sabiendo qué compensaciones está haciendo.
- No vamos a usar el pragma síncrono en SQLite.
- Establecer el pragma SQLite cache_size para que la base de datos encajara en la memoria mejoró el rendimiento en algunas operaciones, como esperábamos.
- La configuración anterior significa que estamos tomando un poco más de riesgo. Utilizaremos la API de copia de seguridad SQLite para minimizar el peligro de falla del disco en una escritura parcial: tomar una instantánea cada N minutos y mantener la última M alrededor. Probé esta API mientras ejecutaba pruebas de rendimiento, y nos dio confianza para seguir este camino.
- Si aún quisiéramos más, podríamos mirar a la basura con el núcleo, pero mejoramos las cosas lo suficiente sin tener que ir allí.
Gracias a @Huygens por varios consejos y sugerencias.