Mysql
 sql >> Database >  >> RDS >> Mysql

Prestazioni della query sulla colonna booleana indicizzata rispetto alla colonna Datetime

Ecco un benchmark MariaDB (10.0.19) con 10 milioni di righe (utilizzando il plug-in sequenza ):

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;

Per misurare il tempo utilizzo set profiling=1 ed esegui show profile dopo aver eseguito una query. Dal risultato della profilazione prendo il valore di Sending data poiché tutto il resto è complessivamente inferiore a un msec.

TINYINT indice:

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

Durata:~ 738 msec

TIMESTAMP indice:

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

Durata:~ 748 msec

Dimensione dell'indice:

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'

Risultato:

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 

Si noti che mentre TIMESTAMP (4 byte) è 4 volte più lungo di TYNYINT (1 byte), la dimensione dell'indice non è nemmeno il doppio. Ma la dimensione dell'indice può essere significativa se non si adatta alla memoria. Quindi, quando cambio innodb_buffer_pool_size da 1G a 50M ottengo i seguenti numeri:

  • TINYINT:~ 960 msec
  • TIMESTAMP:~ 1500 msec

Aggiorna

Per rispondere più direttamente alla domanda ho apportato alcune modifiche ai dati:

  • Invece di TIMESTAMP utilizzo DATETIME
  • Dato che di solito le voci vengono eliminate raramente, uso rand(1)<0.99 (1% eliminato) invece di rand(1)<0.5 (50% cancellato)
  • La dimensione della tabella è cambiata da 10 milioni a 1 milione di righe.
  • SELECT COUNT(*) cambiato in SELECT *

Dimensione dell'indice:

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

Dal 99% di deleted_at i valori sono NULL non vi è alcuna differenza significativa nella dimensione dell'indice, sebbene un DATETIME non vuoto richieda 8 byte (MariaDB).

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

Eliminando entrambi gli indici, entrambe le query vengono eseguite in circa 350 msec. E rilasciando is_active colonna il deleted_at is null la query viene eseguita in 280 msec.

Si noti che questo non è ancora uno scenario realistico. È improbabile che tu voglia selezionare 990.000 righe su 1 milione e consegnarlo all'utente. Probabilmente avrai anche più colonne (forse incluso il testo) nella tabella. Ma mostra che probabilmente non hai bisogno di is_active colonna (se non aggiunge informazioni aggiuntive) e che qualsiasi indice è nel migliore dei casi inutile per selezionare voci non eliminate.

Tuttavia un indice può essere utile per selezionare le righe eliminate:

SELECT * FROM test WHERE is_active = 0;

Viene eseguito in 10 msec con indice e in 170 msec senza indice.

SELECT * FROM test WHERE deleted_at is not null;

Viene eseguito in 11 msec con indice e in 167 msec senza indice.

Eliminare il is_active colonna viene eseguita in 4 msec con indice e in 150 msec senza indice.

Quindi, se questo scenario si adatta in qualche modo ai tuoi dati, la conclusione sarebbe:elimina is_active colonna e non creare un indice su deleted_at colonna se si selezionano raramente voci eliminate. Oppure adatta il benchmark alle tue esigenze e trai le tue conclusioni.