Estamos usando Postgresql 9.1.4 como nuestro servidor de db. He estado tratando de acelerar la velocidad de mi suite de prueba así que me he miró el perfil de la db un poco para ver exactamente lo que está pasando. Estamos utilizando database_cleaner para truncar las tablas al final de las pruebas. SÍ, sé que las transacciones son más rápidas, que no puede usarlos en ciertas circunstancias, así que no estoy preocupado con eso.

Lo que me ocupa, es la razón por TRUNCAMIENTO lleva tanto tiempo (ya que el uso de BORRAR), y por qué se tarda AÚN MÁS en mi servidor CI.

Ahora mismo, de forma local (en un Macbook Air) de un conjunto de pruebas tardan 28 minutos. Seguir a la cola de los registros, cada vez que truncar las tablas… es decir:

TRUNCATE TABLE table1, table2  -- ... etc

se tarda más de 1 segundo para realizar el truncamiento. Seguir a la cola de los registros de nuestro servidor CI (Ubuntu 10.04 LTS), tomar la dura 8 segundos para truncar las tablas y construir una dura 84 minutos.

Cuando me cambié a la :deletion estrategia, a mi local a construir tomó 20 minutos y el servidor CI bajó a 44 minutos. Este es un significativo diferencia y estoy realmente impresionado en cuanto a por qué esto podría ser. He atentos el DB en el servidor CI, tiene 16gb de memoria ram, 4gb de shared_buffers… y un SSD. Todas las cosas buenas. ¿Cómo es posible:

una. que es mucho más lento que mi Macbook Air con 2 gb de ram

b. que el TRUNCAMIENTO es mucho más lenta que ELIMINAR cuando el postgresql docs estado de forma explícita que debe ser mucho más rápido.

Los pensamientos?

  • Estás ejecución de los tests y de la base de datos en el macbook, y las pruebas y base de datos en servidor CI? Son pruebas y base de datos en la misma máquina?
  • Por cierto, lo están haciendo mal… no se puede borrar de la base de datos DESPUÉS de la prueba. Debe hacerlo ANTES de ejecutar la prueba. Usted no puede estar seguro de que la base de datos está desactivada después de las pruebas.
  • Lo postgresql.conf parámetros están en uso? Me pregunto si usted está funcionando con fsync=off (ok si no te importa perder todos sus datos, al igual que en las pruebas), en cuyo caso el equilibrio entre DELETE y TRUNCATE podría ser diferente. También me gustaría estar interesados en su shared_buffers .
  • Cuando te refieres a «el uso de las transacciones», se refiere a la apertura de una transacción, de hacer algunas pruebas, luego de rodar de nuevo? Porque en mi opinión eso es sólo la mitad de una prueba. Mucho puede suceder en COMMIT tiempo si usted está usando SERIALIZABLE transacciones, DEFERRABLE INITIALLY DEFERRED limitaciones, etc, que la comisión de probar los cambios parece sabio.
  • Cuánto tiempo es «etc» por cierto, es decir, cuántas tablas se trunca en un ir? Son tablas muy pequeñas, o contienen un bit de datos? No voy a ser demasiado sorprendido si diminutas mesas son más rápidos para DELETE FROM de TRUNCATE como TRUNCATE tiene que asignar un nuevo archivo de copia de seguridad, escriba los encabezados, cambiar el viejo con ella, vaciar el búfer de caché para la mesa, y fsync. Sospecho que el docs probablemente necesita ser actualizado para reflejar que TRUNCATE es mucho más rápida con tablas grandes, pero no necesariamente con pequeños/los vacíos.
  • shared_buffers= 4 GB; fsync=off; número de mesas es de aproximadamente 50. Cantidad desconocida de datos… pero no más de, digamos, 20 filas por tabla para una prueba en particular
  • y usted está utilizando el cifrado completo del disco? El ML discusión sugiere que puede ser un común de configuración para los usuarios de Mac, pero va a causar terrible rendimiento para cualquier tipo de disco de sincronización.
  • no el mejor de mi conocimiento. tenga en cuenta también que OSX es el más rápido de los dos. Ambos discos son bastante estándar configuración así que no, estoy 99% seguro de que no hay ningún cifrado

InformationsquelleAutor brad | 2012-07-10

4 Comentarios

  1. 137

    Esto ha venido un par de veces recientemente, tanto en el MODO y en el PostgreSQL listas de correo.

    La TL;DR para sus dos últimos puntos:

    (a) La mayor shared_buffers puede ser la razón por la TRUNCATE es más lento en el servidor CI. Diferentes fsync de configuración o el uso de rotación de los medios de comunicación en lugar de unidades de estado sólido también podría ser el culpable.

    (b) TRUNCATE tiene un coste fijo, pero no necesariamente más lento que DELETE, además de que hace más trabajo. Ver la explicación detallada que sigue.

    ACTUALIZACIÓN: UN un debate significativo sobre pgsql-rendimiento surgió de este post. Ver este hilo.

    ACTUALIZACIÓN 2: Mejoras se han añadido a 9.2beta3 que debe ayudar con esto, ver este post.

    Explicación detallada de TRUNCATE vs DELETE FROM:

    Aunque no es un experto en el tema, a mi entender, es que TRUNCATE tiene casi un coste fijo por cada tabla, mientras que DELETE es al menos O(n) para n filas; peor aún si hay claves foráneas referencia a la tabla que se elimina.

    Siempre he asumido que el costo fijo de una TRUNCATE fue menor que el costo de una DELETE en un casi vacío de la tabla, pero esto no es cierto en absoluto.

    TRUNCATE table; hace más de DELETE FROM table;

    El estado de la base de datos después de un TRUNCATE table es la misma como si la hubiera lugar de ejecución:

    • DELETE FROM table;
    • VACCUUM (FULL, ANALYZE) table; (9.0+ solo, véase la nota de pie de página)

    … aunque, por supuesto, TRUNCATE en realidad no lograr sus efectos con un DELETE y un VACUUM.

    El punto es que DELETE y TRUNCATE hacer cosas diferentes, de modo que no sólo la comparación de dos comandos con idénticos resultados.

    Un DELETE FROM table; permite muertos filas y engordar a permanecer, permite a los índices de llevar muerto entradas, no se actualiza la tabla de estadísticas que utiliza el planificador de consultas, etc.

    Un TRUNCATE le da una completamente nueva tabla y los índices como si fueran solo CREATEed. Es como si se eliminan todos los registros, vuelvan a indexar la mesa e hizo un VACUUM FULL.

    Si no te importa si hay crud a la izquierda en la tabla, porque estás a punto de ir y llenar de nuevo, puede ser mejor usar DELETE FROM table;.

    Porque no ejecuta VACUUM usted encontrará que los muertos filas y las entradas de índice de acumular exceso de datos que deben ser analizados a continuación, se omiten; esto ralentiza a todas sus preguntas abajo. Si las pruebas no deben crear y eliminar toda esa cantidad de datos que usted puede no notar o atención, y que siempre se puede hacer un VACUUM o dos parte del camino a través de la ejecución de prueba si lo hace. Mejor, vamos agresivo autovacuum configuración de asegurar que autovacuum hace por usted en el fondo.

    Usted todavía puede TRUNCATE todas sus mesas después de la todo suite de prueba se ejecuta para asegurarse de que no hay efectos se acumulan a través de muchas pistas. En 9.0 y versiones más recientes, VACUUM (FULL, ANALYZE); a nivel mundial sobre la mesa es al menos tan bueno si no mejor, y es mucho más fácil.

    IIRC Pg tiene un par de optimizaciones que significa que se puede notar cuando la transacción es el único que puede ver la mesa y de inmediato marca de los bloques como libre de todos modos. En las pruebas, cuando he querido crear hinchazón he tenido que tener más de una conexión simultánea a hacerlo. Yo no se basan en esto, sin embargo.

    DELETE FROM table; es muy barato para tablas pequeñas sin f/k refs

    A DELETE todos los registros de una tabla sin clave externa hace referencia a ello, todos Pg tiene que hacer una secuencia de exploración de tabla y establecer el xmax de las tuplas encontrado. Esta es una muy barato operación – básicamente lineal de lectura y un semi-lineal de la escritura. AFAIK no tienen que tocar los índices siguen a punto para las tuplas muertas hasta que se hayan limpiado por un VACUUM que también las marcas de los bloques en la tabla que contiene sólo las tuplas muertas como libre.

    DELETE sólo resulta caro si hay muchas de registros, si hay un montón de extranjeros referencias clave que deben ser revisados, o si se cuenta el posterior VACUUM (FULL, ANALYZE) table; necesario para que coincida con TRUNCATE‘s efectos en el costo de su DELETE .

    En mis pruebas aquí, un DELETE FROM table; era típicamente 4x más rápido que TRUNCATE en 0,5 ms vs 2ms. Eso es una prueba de la DB en un SSD, corriendo con fsync=off porque no me importa si pierdo todos los datos. Por supuesto, DELETE FROM table; no hace todo el mismo trabajo, y si sigo con un VACUUM (FULL, ANALYZE) table; es una forma mucho más caro 21ms, por lo que el DELETE es sólo una victoria si yo en realidad no necesitan la tabla prístina.

    TRUNCATE table; hace mucho más del costo fijo de trabajo y servicio de limpieza de DELETE

    Por el contrario, un TRUNCATE tiene que hacer un montón de trabajo. Se debe asignar de nuevo los archivos de la tabla, su BRINDIS de mesa, si los hubiere, y cada índice de la tabla ha. Los encabezados deben de ser escritos en los archivos y los catálogos del sistema puede necesitar actualizar demasiado (no se sabe en que punto, no lo he comprobado). Luego se tiene a reemplazar los archivos antiguos con los nuevos, o quitar las viejas, y tiene que garantizar el sistema de archivos ha acertado con los cambios, con una operación de sincronización – fsync() o similares – que generalmente los vaciados de todos los búferes de disco. No estoy seguro de si la sincronización se omite si usted está funcionando con el (los datos de-comer) opción fsync=off .

    Me enteré recientemente que TRUNCATE también debe vaciar todos PostgreSQL búferes relacionados con la mesa de edad. Esto puede tomar no trivial de la cantidad de tiempo que con enorme shared_buffers. Sospecho que esto es por qué es más lento en su servidor CI.

    El equilibrio

    De todos modos, se puede ver que un TRUNCATE de una tabla que tiene asociado un BRINDIS tabla (la mayoría lo hacen) y varios índices podría tomar un par de momentos. No mucho, pero más de un DELETE de una casi vacía de la tabla.

    Por consiguiente, podría ser mejor hacer un DELETE FROM table;.

    Nota: en el DBs antes de 9.0, CLUSTER table_id_seq ON table; ANALYZE table; o VACUUM FULL ANALYZE table; REINDEX table; sería de cerca equivalente a TRUNCATE. El VACUUM FULL impl cambiado a una mucho mejor en 9.0.

    • Y tienen diferentes tipos de cerraduras ela bien: bloqueo de tabla vs bloqueo de fila.
    • Gracias por la respuesta completa! De acuerdo a los docs >> [De TRUNCAR] tiene el mismo efecto que un incompetente ELIMINAR en cada tabla, pero ya que en realidad no escanear las tablas es más rápido. Además, se recupera espacio en el disco inmediatamente, en lugar de exigir una posterior operación en VACÍO. >> Así que no creo que en realidad aspira después de truncar. Se sugiere también que el hecho de que tengo 4GB shared_buffers es en realidad un perjuicio para el rendimiento?
    • Para el caso específico de TRUNCATE, sí, estoy diciendo que en mi entendimiento es que los grandes shared_buffers puede ralentizar las cosas. Yo no he probado a mí mismo, pero es que suena de ML de discusión. Y no, no hay ningún VACCUM hacer después de un truncado – mientras truncar tiene el efecto de una DELETE FROM seguido por un VACUUM FULL ANALYZE;, que en realidad no funciona de esa manera, o realizar los pasos.
    • ah, ok, gracias por la aclaración.
    • gracias por el enlace para que ML por cierto… es genial ver las conversaciones que rodean a temas como este
    • Encantados de ayudarle. Por favor, únase, y si se puede, nos ayudan a recoger algunos datos de rendimiento para entender mejor por qué TRUNCATE parece por tanto más lento para algunos usuarios, especialmente a los usuarios de Mac.
    • ya va a hacer cuando tengo la oportunidad… sólo quería volver a iterar a pesar de que el pg es de hecho MUCHO más RÁPIDO para mí en OSX que es en Linux. A pesar de que mi linux tiene 16 gb de ram y es en general mucho beefier de mi Macbook Air. He sintonizado el linux, postgresql.conf y no has tocado mi OSX uno. Es bastante extraño.
    • 9.2beta3 debe contener mejoras para esto. Consulte archives.postgresql.org/message-id/…
    • Por curiosidad, ¿cuál es su definición de una «mesa»? 1 millón de filas o menos?
    • Muy hardware y SO-dependiente, de verdad. También depende de cosas como por ejemplo si se tiene un BRINDIS lado de la mesa o no. Me gustaría tienden a TRUNCATE nada más que un par de miles de registros, pero no he hecho ninguna prueba/bencharking en el punto de cruce como no he tenido una situación en la que yo he tenido el cuidado suficiente para que valga la pena el tiempo.
    • Yo en realidad no entiendo por qué un truncado-como eliminar no es posible. En muchas aplicaciones (100 por ciento de los nuestros), los muertos en las filas son una molestia. No tenemos otras las transacciones que se ejecutan, no hay simultaneidad, etc. Como resultado, nos encontramos con que a menudo es más rápido para truncar y rellenar tablas (incluso de gran tamaño-ish) y a lo más que el dolor de cabeza de la eliminación y sustitución de las filas de sólo un par de filas específicas, a continuación, pasar la aspiradora.
    • reversiones. si su txn aborta, en el servidor o el cliente se bloquea, etc. Puf, los datos han ido.
    • El timbre. Gracias, entiendo eso, pero no es un problema para cualquiera de nuestra base de datos utiliza PostgreSQL como un área de preparación de datos se construye sobre la marcha. Muchos otros han aplicaciones similares, donde Postgres no es el único récord, pero el almacenamiento de los datos manipulados/construidas a partir de otras fuentes. El riesgo de pérdida de datos es cero para nosotros, para un rápido, total borrar sería lo ideal.
    • De hecho, hay casos especiales donde PostgreSQL expresiva/potente motor de consulta es necesario, pero su robustez no es tanto. Usted puede sintonizar Pg a ser mucho menos de choque de seguro de varias maneras pero no se puede deshabilitar WAL registro y MVCC, no hay manera de hacerlo a la fuerza directa de la tupla que más escribe en el montón. Hay un par de optimizaciones como COPY FREEZE y que probablemente se podría trabajar con la comunidad postgres para añadir más. Probablemente no es totalmente no-transaccional, aunque.

  2. 5

    Brad, sólo para hacerle saber. He mirado bastante profundamente en una pregunta similar.

    Relacionadas con la pregunta: 30 tablas con pocas filas – TRUNCAR la manera más rápida de los vacíos y de restablecimiento de secuencias adjuntos?

    También revise este tema y este de pull request:

    https://github.com/bmabey/database_cleaner/issues/126

    https://github.com/bmabey/database_cleaner/pull/127

    También este hilo: http://archives.postgresql.org/pgsql-performance/2012-07/msg00047.php

    Lo siento por escribir esto como una respuesta, pero no he encontrado ningún comentario enlaces, tal vez porque hay demasiado los comentarios que ya hay.

    • hey gracias stanislaw. De hecho vi a esos puestos, que me llevó a la actualización de db limpiador de uso de la masa de truncamiento. Que, sin embargo, hizo poco para ayudar a mí. Todavía en la PG parece que la eliminación de la estrategia es mucho más rápida, que es lo que yo he terminado de usar.
  3. 0

    Un par de métodos alternativos a considerar:

    • Crear una base de datos vacía con estática «accesorio» de los datos en ella, y ejecutar las pruebas en que. Cuando haya terminado, simplemente basta con colocar la base de datos, que debe ser rápido.
    • Crear una nueva tabla llamada «test_ids_to_delete» que contiene las columnas de la tabla de nombres y clave primaria id. Actualización de su lógica de eliminación para insertar el id de la tabla de nombres en esta tabla, que será mucho más rápidas que la elimina. Luego, escribe una secuencia de comandos para ejecutar «sin conexión» para eliminar realmente los datos, ya sea después de toda la ejecución de la prueba ha terminado, o durante la noche.

    El primero es una «sala limpia», mientras que la segunda significa que habrá algunos datos de prueba va a persistir en la base de datos por más tiempo. El «sucio» enfoque con la línea elimina es lo que estoy usando para un conjunto de pruebas con cerca de 20.000 pruebas. Sí, a veces hay problemas debido a la necesidad de «extra» de los datos de prueba en el dev de la base de datos, pero a veces. Pero a veces esta «suciedad» nos ha ayudado a encontrar y corregido el bug porque el «desorden» mejor simulado una situación real, en un camino que limpiar la habitación enfoque nunca lo hará.

  4. 0

    Me he encontrado problema similar últimamente, es decir:

    1. El tiempo para ejecutar el conjunto de pruebas que utiliza DatabaseCleaner varía ampliamente entre los diferentes sistemas comparables de hardware,
    2. Cambiar DatabaseCleaner estrategia para :deletion siempre ~10x mejora.

    La raíz de la causa de la lentitud era un sistema de archivos con journaling (ext4) utilizados para el almacenamiento de base de datos. Durante la operación TRUNCAR el diario de demonio (jbd2) fue el uso de ~90% de e /s de disco capacidad. No estoy seguro de si esto es un error, un caso extremo o en realidad de un comportamiento normal en estas circunstancias. Esto explica sin embargo ¿por qué TRUNCAR fue mucho más lento que ELIMINAR – se genera mucho más que las escrituras en disco. Como yo no quería en realidad el uso ELIMINAR he recurrido a la configuración de fsync=off y fue suficiente para mitigar este problema (la seguridad de los datos no era importante en este caso).

Dejar respuesta

Please enter your comment!
Please enter your name here