2009-04-25 19 views
12

Tengo una base de datos Sqlite3 con una tabla y una clave principal que consta de dos enteros, y estoy tratando de insertar muchos datos en ella (es decir, alrededor de 1 GB)Sqlite3: ¿Desactivar el índice de clave principal durante la inserción?

El problema que tengo es que la creación de la clave principal también implícitamente crea un índice, que en mi caso se infiltra en un rastreo después de algunas confirmaciones (y eso sería porque el archivo de la base de datos está en NFS ... suspiro).

Por lo tanto, me gustaría de alguna manera desactivar temporalmente ese índice. Hasta ahora, mi mejor plan consistía en eliminar el índice automático de la clave principal, pero parece que a SQLite no le gusta y arroja un error si intento hacerlo.

Mi segundo mejor plan consistiría en que la aplicación realizara copias transparentes de la base de datos en la unidad de red, realizando modificaciones y luego fusionándola. Tenga en cuenta que a diferencia de la mayoría de las preguntas SQlite/NFS, no necesito concurrencia de acceso.

¿Cuál sería la forma correcta de hacer algo como eso?

ACTUALIZACIÓN:

me olvidó especificar las banderas ya estoy usando:

PRAGMA synchronous = OFF 
PRAGMA journal_mode = OFF 
PRAGMA locking_mode = EXCLUSIVE 
PRAGMA temp_store = MEMORY 

ACTUALIZACIÓN 2: estoy, de hecho, la inserción de artículos en lotes, sin embargo cada lado el lote es más lento de comprometer que el anterior (supongo que esto tiene que ver con el tamaño del índice). Intenté hacer lotes de entre 10k y 50k tuplas, cada uno de los cuales constaba de dos enteros y un flotador.

Respuesta

10
  1. No se puede eliminar el índice incrustado ya que es la única dirección de la fila.
  2. Fusiona tus 2 claves enteras en una sola tecla larga = (clave1 < < 32) + tecla2; y hacer esto como un INTEGER PRIMARY KEY en el esquema youd (en ese caso, tendrá que sólo el 1 índice)
  3. Establecer tamaño de página para la nueva base de datos, al menos, 4096
  4. eliminar cualquier índice adicional, excepto primaria
  5. rellenar los datos en el orden CLASIFICADO para que la clave primaria esté creciendo.
  6. comandos Reciclar, no crean cada vez que desde la cadena
  7. Establecer tamaño de caché de páginas de más memoria que le queda (recordemos que el tamaño de caché es en número de páginas, pero no el número de bytes)
  8. Cometa cada 50000 artículos.
  9. Si tiene índices adicionales - crearlos después de que todos los datos en la tabla es

Si vas a ser capaz de fusionar clave (creo que está utilizando 32 bits, mientras que el uso de SQLite de 64 bits, por lo que es posible) y complete los datos en orden ordenado. Apuesto a que completará su primer Gb con el mismo rendimiento que el segundo y ambos serán lo suficientemente rápidos.

+0

Mantener la cantidad de datos por uno INSERTAR declaración en línea con el parámetro cache_size parece hacer el truco. Obviamente, hay más memoria caché, se pueden insertar más elementos de una vez. También parece que puedo hacer una confirmación al final de todo después de todo. –

+0

Bueno, puedes. Pero el truco principal para cualquier operación de inserción es O (1) es completar los datos ordenados por ese índice, pero en el caso de que sus datos se ajusten a la memoria caché, todo es realmente rápido. Es razonable mantener el tamaño de compromiso menor que el tamaño de caché, de lo contrario, sqlite se verá obligado a moverlo al disco. – Mash

6

¿Está haciendo el INSERT de cada nuevo como una transacción individual?

Si utiliza BEGIN TRANSACTION y INSERT filas en lotes, entonces creo que el índice solo se reconstruirá al final de cada transacción.

+0

Lo hará. Estaba a punto de sugerir eso también :) –

+0

Sí, pero ¿puedo exprimir un gigabyte completo en una transacción? Casi lo hice por accidente (olvidé poner la declaración de compromiso en algún lugar) y obtuve algunos errores de E/S del disco a la mitad, aunque no estoy seguro si está relacionado ... –

Cuestiones relacionadas