sql >> Base de Datos >  >> RDS >> Mysql

Rendimiento de la consulta en la columna booleana indexada frente a la columna de fecha y hora

Aquí hay un punto de referencia de MariaDB (10.0.19) con 10 millones de filas (usando el complemento de secuencia ):

drop table if exists test;
CREATE TABLE `test` (
    `id` MEDIUMINT UNSIGNED NOT NULL,
    `is_active` TINYINT UNSIGNED NOT NULL,
    `deleted_at` TIMESTAMP NULL,
    PRIMARY KEY (`id`),
    INDEX `is_active` (`is_active`),
    INDEX `deleted_at` (`deleted_at`)
) ENGINE=InnoDB
    select seq id
        , rand(1)<0.5 as is_active
        , case when rand(1)<0.5 
            then null
            else '2017-03-18' - interval floor(rand(2)*1000000) second
        end as deleted_at
    from seq_1_to_10000000;

Para medir el tiempo uso set profiling=1 y ejecuta show profile después de ejecutar una consulta. Del resultado del perfil tomo el valor de Sending data ya que todo lo demás es en total menos de un mseg.

TINYINT índice:

SELECT COUNT(*) FROM test WHERE is_active = 1;

Tiempo de ejecución:~ 738 ms

MARCA DE TIEMPO índice:

SELECT COUNT(*) FROM test WHERE  deleted_at is null;

Tiempo de ejecución:~ 748 ms

Tamaño del índice:

select database_name, table_name, index_name, stat_value*@@innodb_page_size
from mysql.innodb_index_stats 
where database_name = 'tmp'
  and table_name = 'test'
  and stat_name = 'size'

Resultado:

database_name | table_name | index_name | stat_value*@@innodb_page_size
-----------------------------------------------------------------------
tmp           | test       | PRIMARY    | 275513344 
tmp           | test       | deleted_at | 170639360 
tmp           | test       | is_active  |  97107968 

Tenga en cuenta que mientras TIMESTAMP (4 bytes) es 4 veces más largo que TYNYINT (1 byte), el tamaño del índice no es ni siquiera el doble. Pero el tamaño del índice puede ser significativo si no cabe en la memoria. Así que cuando cambio innodb_buffer_pool_size desde 1G a 50M obtengo los siguientes números:

  • TINYINT:~ 960 ms
  • MARCA DE TIEMPO:~ 1500 ms

Actualizar

Para abordar la pregunta de manera más directa, hice algunos cambios en los datos:

  • En lugar de TIMESTAMP uso DATETIME
  • Dado que las entradas rara vez se eliminan, uso rand(1)<0.99 (1 % eliminado) en lugar de rand(1)<0.5 (50% eliminado)
  • El tamaño de la tabla cambió de 10 millones a 1 millón de filas.
  • SELECT COUNT(*) cambiado a SELECT *

Tamaño del índice:

index_name | stat_value*@@innodb_page_size
------------------------------------------
PRIMARY    | 25739264
deleted_at | 12075008
is_active  | 11026432

Dado que el 99% de deleted_at los valores son NULL, no hay una diferencia significativa en el tamaño del índice, aunque un DATETIME no vacío requiere 8 bytes (MariaDB).

SELECT * FROM test WHERE is_active = 1;      -- 782 msec
SELECT * FROM test WHERE deleted_at is null; -- 829 msec

Al eliminar ambos índices, ambas consultas se ejecutan en aproximadamente 350 mseg. Y soltando el is_active columna el deleted_at is null la consulta se ejecuta en 280 ms.

Tenga en cuenta que esto todavía no es un escenario realista. Es poco probable que desee seleccionar 990 000 filas de 1 millón y entregárselas al usuario. Probablemente también tendrá más columnas (quizás incluyendo texto) en la tabla. Pero muestra que probablemente no necesite el is_active columna (si no agrega información adicional), y que cualquier índice es, en el mejor de los casos, inútil para seleccionar entradas no eliminadas.

Sin embargo, un índice puede ser útil para seleccionar filas eliminadas:

SELECT * FROM test WHERE is_active = 0;

Se ejecuta en 10 ms con índice y en 170 ms sin índice.

SELECT * FROM test WHERE deleted_at is not null;

Se ejecuta en 11 ms con índice y en 167 ms sin índice.

Soltando el is_active columna se ejecuta en 4 mseg con índice y en 150 mseg sin índice.

Entonces, si este escenario de alguna manera se ajusta a sus datos, la conclusión sería:elimine el is_active columna y no cree un índice en deleted_at columna si rara vez selecciona entradas eliminadas. O ajuste el punto de referencia a sus necesidades y saque sus propias conclusiones.