2010-11-12 11 views
9

Un colega me dijo que la ejecución de una declaración SQL siempre coloca los datos en RAM/swap en el servidor de la base de datos. Por lo tanto, no es práctico seleccionar grandes conjuntos de resultados.¿La ejecución de una declaración siempre toma en memoria el conjunto de resultados?

pensé que tal código

my $sth = $dbh->prepare('SELECT million_rows FROM table'); 
while (my @data = $sth->fetchrow) { 
    # process the row 
} 

recupera la fila del conjunto de resultados por fila, sin que se carga en la memoria RAM. Pero no puedo encontrar ninguna referencia a esto en documentos DBI o MySQL. ¿Cómo se crea y recupera realmente el conjunto de resultados? ¿Funciona igual para simples selects y joins?

+0

pregunta sobre el propósito, ¿por qué necesita obtener millones de filas de registro e iterar recuperar todo? 'mysqldump' debería ser más apropiado – ajreal

+0

@ajreal: Necesito procesar todas las filas en orden de inserción y generar algunos informes. – planetp

+0

bien, ¿es racional hacer eso? Usando la función mysql para generar vista, ¿la tabla temporal no es suficiente para el informe? o incluso considerar el volcado de los GRANDES resultados en un archivo, y abrir el archivo para procesar – ajreal

Respuesta

6

Su colega tiene razón.

De forma predeterminada, el módulo perl DBD :: mysql usa mysql_store_result que realmente lee en todos los datos SELECT y lo almacena en caché en la memoria RAM. A menos que cambie ese valor predeterminado, cuando recupera fila por fila en DBI, simplemente los está leyendo de ese búfer de memoria.

Esto es generalmente lo que desea a menos que tenga conjuntos de resultados muy grandes. De lo contrario, hasta que obtenga la última información de mysqld, tiene que mantener esos datos listos y mi entendimiento es que causa bloques en las escrituras en las mismas filas (¿bloques? Tablas?).

Tenga en cuenta que las máquinas modernas tienen mucha RAM. Un conjunto de resultados de un millón de filas generalmente no es un gran problema. Incluso si cada fila es bastante grande a 1 KB, eso es solo 1 GB de RAM más gastos generales.

Si va a procesar millones de filas de BLOB, quizás desee mysql_use_result - o si desea SELECCIONAR esas filas en fragmentos con usos progresivos de LIMIT x,y.

Consulte mysql_use_result y mysql_store_result en perldoc DBD::mysql para obtener más información.

+0

+1, no sabía que DBD :: mysql hace eso. Sin embargo, tu comentario de que no deberías preocuparte a menos que estés en peligro de agotar RAM es un MAL consejo: como regla general, solo debes obtener los datos que necesitas y si no necesitas millones de filas (y raramente lo haces), no deberías obtenerlos todos. Tal enfoque arruinará la escalabilidad más allá de la reparación (la situación es un poco mejor si la biblioteca almacena en caché en el nivel de la aplicación y no en la sesión, pero aún no es bueno; si este caché a menudo se invalida, está obteniendo repetidamente 1GB de datos donde necesita mucho menos) – Unreason

1

No estoy muy familiarizado con esto, pero me parece que DBD :: mysql puede buscar todo por adelantado o solo según sea necesario, en función del atributo mysql_use_result. Consulte la documentación DBD :: mysql y MySQL.

5

Esto no es cierto (si hablamos del servidor de la base de datos, no de las capas del cliente).

MySQL puede amortiguar todo el conjunto de resultados, pero esto no se hace necesariamente, y si se hace, no necesariamente en RAM.

El conjunto de resultados se almacena temporalmente si está utilizando vistas en línea (SELECT FROM (SELECT …)), la consulta tiene que ordenar (que se muestra como using filesort), o el plan requiere la creación de una tabla temporal (que se muestra como using temporary en el plan de consulta) .

Incluso si using temporary, MySQL solo mantiene la tabla en la memoria cuando su tamaño no supera el límite establecido en tmp_table. Cuando la tabla crece por encima de este límite, se convierte de memory en MyISAM y se almacena en el disco.

Sin embargo, usted puede instruir explícitamente MySQL para almacenar el conjunto de resultados al agregar la instrucción SQL_BUFFER_RESULT al extremo SELECT.

Consulte el docs para obtener más información.

3

No, así no es como funciona.

La base de datos no guardará filas en RAM/swap.

Sin embargo, intentará, y mysql intenta mucho aquí, almacenar tanto como sea posible (índices, resultados, etc.). Su configuración de mysql proporciona valores para los búferes de memoria disponibles para diferentes tipos de cachés (para diferentes tipos de motores de almacenamiento): no debe permitir que este caché se intercambie.

prueba que
En pocas palabras - que debe ser muy fácil de probar sólo que esta utilizando cliente (no sé DBI de Perl, que podría, pero lo dudo, estar haciendo algo que obliga a MySQL para cargar todo en preparar). De todas formas ... pruébelo:

Si realmente emite un prepararse en SELECT SQL_NO_CACHE million_rows FROM table y luego obtiene solo algunas filas de millones. Luego debe comparar el rendimiento con SELECT SQL_NO_CACHE only_fetched_rows FROM table y ver cómo funcionan esas tarifas. Si el rendimiento es comparable (y rápido), entonces creo que puede llamar el farol de su colega.

Además, si habilita el registro de las declaraciones realmente emitidas a mysql y nos da una transcripción de eso, nosotros (personas sin perl) podemos dar una respuesta más definitiva sobre lo que haría mysql.

Cuestiones relacionadas