2012-10-03 43 views
6

tengo una base de datos local SQLiteSQLite: ¿la forma más rápida de leer datos de la base de datos SQLite?

Tabla detallada

-- Describe PREFIX_LIST 
CREATE TABLE PREFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY) 

-- Describe SUFFIX_LIST 
CREATE TABLE SUFFIX_LIST(ITEM VARCHAR(25) PRIMARY KEY) 

-- Describe VALID_LIST 
CREATE TABLE VALID_LIST (
    "PART1" TEXT, 
    "PART2" TEXT, 
    PRIMARY KEY(PART1, PART2) 
) 

ahora esta lista es realmente enorme, y necesito que guardar los datos de ella.

Aquí está mi implementación.

SQLiteConnection con = null; 
SQLiteCommand cmd = null; 
Connect(DbPath, ref con, ref cmd); 

cmd.CommandText = 
    "SELECT PART1 || '@' || PART2 FROM VALID_LIST 
WHERE NOT EXISTS 
    (SELECT * FROM PREFIX_LIST WHERE VALID_LIST.PART1 LIKE '%' || ITEM || '%') 
    AND NOT EXISTS 
    (SELECT * FROM SUFFIX_LIST WHERE VALID_LIST.PART2 LIKE '%' || ITEM || '%')"; 

var reader = cmd.ExecuteReader(); 

if (reader.HasRows) 
{ 
    string savePath; 

    if (SaveTextFile(out savePath) == DialogResult.OK) 
    { 
     TextWriter writer = new StreamWriter(savePath); 
     while (reader.Read()) 
     { 
      writer.WriteLine(reader.GetString(0)); 
     } 
     writer.Close(); 
     writer.Dispose(); 
    } 

} 

reader.Close(); 
reader.Dispose(); 
cmd.Dispose(); 
con.Close(); 
con.Dispose(); 

MessageBox.Show("List Saved!.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); 

Necesito una mejor manera en que puedo guardar la lista más rápido. entradas totales en VALID_LIST es 2639117

y tardó 15 minutos para salvarlo de la consulta SQL anterior!

por favor lmk si la consulta sql se puede optimizar!

Gracias de antemano

+2

Subconsulta correlacionada + 'LIKE' = rendimiento enorme hit – cdhowie

+0

@cdhowie - lo sé, pero ¿qué otra solución? ¡Creo que la consulta debe ser optimizada de alguna manera! –

+0

No creo que haya una manera fácil de optimizar esto sin alterar por completo su esquema. – cdhowie

Respuesta

6

consultas con LIKE van a ser muy lento, en general, a menos que el comodín está unido al sufijo. Un predicado como LIKE '%foo' no se puede indexar a través de la indexación típica de cadenas.

Sin embargo, puede reemplazar el uso pesado LIKE en sqlite con su característica full text search (FTS).

Los módulos de extensión FTS3 y FTS4 permite a los usuarios crear tablas especiales con un sistema incorporado en el índice de texto completo (en lo sucesivo "FTS tablas"). El índice de texto completo permite al usuario consultar de manera eficiente la base de datos todas las filas que contienen una o más palabras (en lo sucesivo "tokens"), incluso si la tabla contiene muchos documentos grandes.

Tienen an example que se ven prometedores en términos de rendimiento en su caso de uso.

CREATE VIRTUAL TABLE enrondata1 USING fts3(content TEXT);  /* FTS3 table */ 
CREATE TABLE enrondata2(content TEXT);      /* Ordinary table * 

SELECT count(*) FROM enrondata1 WHERE content MATCH 'linux'; /* 0.03 seconds */ 
SELECT count(*) FROM enrondata2 WHERE content LIKE '%linux%'; /* 22.5 seconds */ 
+0

Creo que lo tienes al revés: los prefijos pueden usar índices, pero los sufijos no. – cdhowie

+0

@cdhowie Estoy de acuerdo, me refería a dónde se colocó el comodín. He aclarado mi respuesta. –

+0

Veo lo que querías decir ahora. Fue un poco ambiguo, gracias por aclarar. – cdhowie

2

Considere la posibilidad de utilizar la búsqueda de texto completo.

Para que esto funcione, los valores en PREFIX y SUFFIX tienen que ser tokenizados (deben ser palabras separadas), y el ITEM que está intentando hacer coincidir debe ser un token distinto en uno de estos valores (no parte de una palabra o dos palabras juntas). Por ejemplo, las cadenas en PREFIX y SUFFIX tienen que ser algo así como 'VERDE AZUL ROJO' o 'PERRO, GATO, CAPÍBARA' y los valores para ARTÍCULO deben ser ROJO, AZUL, VERDE, PERRO, CAT o CAPÍBARA.

Si se cumplen estas condiciones, puede habilitar la búsqueda de texto completo, recrear estas tablas como tablas de texto completo y reemplazar LIKE (y los comodines) con MATCH. En este caso, SQLite mantendrá el índice en cada token que se encuentre en PREFIX o SUFFIX y esa parte de la búsqueda será mucho, mucho más rápida.

Desafortunadamente, habilitar FTS en SQlite implica compilar el producto desde el código fuente con uno o más conjuntos de banderas en tiempo de compilación establecidos. No tengo experiencia con esto

+0

thnx para toda la información! parece que tengo que quedarme en mi atm de solución, ¡aunque sea más lento! –

+0

¿Es verdad que su ÍTEM coincide con palabras individuales? Si es así, coloque las palabras, una a la vez, en sus propias filas. Puedes hacer que eso funcione muy rápido. –

+0

lo siento por mi mal inglés, pero lo que estoy tratando de hacer a través de sql es, asegúrese de que todos mis artículos en valid_list.part1 no coincidan parcialmente con todos los artículos en prefix_list.item –

0

No estoy seguro de si esto es lo que quiere, pero ayudará a acelerar el proceso de escritura. Intente acumular las cadenas que lee de la base de datos en un generador de cadenas y luego escriba en el archivo. Por ejemplo, puede leer 100k de cadenas y luego escribir esas 100k en el archivo de una vez.

StringBuilder builder = new StringBuilder(); 
    int count = 0; //to limit the number of rows stored in string builder. 
    while (reader.Read()) 
    { 

     builder.AppendLine(reader.GetString(0)); 
     count++; 

     //store every 100k or so rows at once. 
     //This number depends on how much RAM 
     //you can allocate towards storing the string of rows. 
     //If you have 2GB of free RAM 
     //this number can easily be 1 million but it always depends on the 
     //size of each string stored in database. 
     if(count == 100000) 
     { 
      File.AppendAllText(path, builder.ToString()); //Append all rows to the file 
      builder.Clear(); //clear the string for next 100k rows of data 
      count = 0; //Clear the counter value 
     } 
     count++ 
    } 

Avísame si te ayudó.

Cuestiones relacionadas