Ho un problema con INDICARE un DATETIME (o anche una data) come prima parte del mio PRIMARY KEY.
Uso MySQL 5.5
Ecco i miei due tavoli:
-- This is my standard table with dateDim as a dateTime
CREATE TABLE `stats` (
`dateDim` datetime NOT NULL,
`accountDim` mediumint(8) unsigned NOT NULL,
`execCodeDim` smallint(5) unsigned NOT NULL,
`operationTypeDim` tinyint(3) unsigned NOT NULL,
`junkDim` tinyint(3) unsigned NOT NULL,
`ipCountryDim` smallint(5) unsigned NOT NULL,
`count` int(10) unsigned NOT NULL,
`amount` bigint(20) NOT NULL,
PRIMARY KEY (`dateDim`,`accountDim`,`execCodeDim`,`operationTypeDim`,`junkDim`,`ipCountryDim`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- Here is a copy with datDim as an integer
CREATE TABLE `stats_todays` (
`dateDim` int(11) unsigned NOT NULL,
`accountDim` mediumint(8) unsigned NOT NULL,
`execCodeDim` smallint(5) unsigned NOT NULL,
`operationTypeDim` tinyint(3) unsigned NOT NULL,
`junkDim` tinyint(3) unsigned NOT NULL,
`ipCountryDim` smallint(5) unsigned NOT NULL,
`count` int(10) unsigned NOT NULL,
`amount` bigint(20) NOT NULL,
PRIMARY KEY (`dateDim`,`accountDim`,`execCodeDim`,`operationTypeDim`,`junkDim`,`ipCountryDim`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Riempo entrambe le tabelle con esattamente gli stessi dati (circa 10.000.000)
Ma:
- la tabella delle statistiche usa DATETIME per dateDim
- stats_todays usa un INTEGER con TO_DAYS () per dateDim
La mia domanda è: perché MySQL NON UTILIZZA LA CHIAVE PRIMARIA quando la prima parte dell'indice è un datetime ??? È molto strano poiché con gli stessi dati ma consolidati con un INTEGER e TO_DAYS (dateDim) la stessa richiesta oscilla ....
Esempio con tabella delle statistiche (e datetime):
SELECT *
FROM `stats`
WHERE
dateDim = '2014-04-03 00:00:00'
AND accountDim = 4
AND execCodeDim = 9
AND operationTypeDim = 1
AND junkDim = 5
AND ipCountryDim = 3
=> 1 result (4.5sec)
Explain:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE stats ALL NULL NULL NULL NULL 8832329 Using where
Stessa richiesta sull'altra tabella stats_todays (Con INTEGER e TO_DAYS ())
EXPLAIN SELECT *
FROM `stats_todays`
WHERE
dateDim = TO_DAYS('2014-04-03 00:00:00')
AND accountDim = 4
AND execCodeDim = 9
AND operationTypeDim = 1
AND junkDim = 5
AND ipCountryDim = 3
=> Result 1 row (0.0003 sec)
Explain:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE stats_todays const PRIMARY PRIMARY 13 const,const,const,const,const,const 1
Se leggi l'intero post, capisci che non si tratta di un problema di cardinalità bassa poiché la richiesta funziona esattamente con la stessa cardinalità con un campo INTEGER dateDim ....
Ecco alcuni dettagli avanzati:
SELECT COUNT( DISTINCT dateDim )
FROM stats_todays
UNION ALL
SELECT COUNT( DISTINCT dateDim )
FROM stats;
Result:
COUNT(DISTINCT dateDim)
2192
2192
Ecco la descrizione dell'INDICE:
SHOW INDEXES FROM `stats`
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
stats 0 PRIMARY 1 dateDim A 6921 NULL NULL BTREE
stats 0 PRIMARY 2 accountDim A 883232 NULL NULL BTREE
stats 0 PRIMARY 3 execCodeDim A 8832329 NULL NULL BTREE
stats 0 PRIMARY 4 operationTypeDim A 8832329 NULL NULL BTREE
stats 0 PRIMARY 5 junkDim A 8832329 NULL NULL BTREE
stats 0 PRIMARY 6 ipCountryDim A 8832329 NULL NULL BTREE
SHOW INDEXES FROM `stats_todays`
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
stats_todays 0 PRIMARY 1 dateDim A 7518 NULL NULL BTREE
stats_todays 0 PRIMARY 2 accountDim A 4022582 NULL NULL BTREE
stats_todays 0 PRIMARY 3 execCodeDim A 8045164 NULL NULL BTREE
stats_todays 0 PRIMARY 4 operationTypeDim A 8045164 NULL NULL BTREE
stats_todays 0 PRIMARY 5 junkDim A 8045164 NULL NULL BTREE
stats_todays 0 PRIMARY 6 ipCountryDim A 8045164 NULL NULL BTREE
SELEZIONA dateDim, COUNT (*) DA stats GROUP BY dateDim WITH ROLLUP
- dice che ci sono 2192 date diverse e la ripartizione è regolare (circa 3000 - 4000 righe per data)
- ci sono 8 831 990 righe nella tabella
- Lo stesso per l'altro tavolo
- Ho provato con COVERING INDEX (sostituendo * con tutte le colonne PK) => non è cambiato nulla
- Ho provato a forzare | usa index => non è cambiato nulla
- Lo stesso con il campo data invece datetime
- Lo stesso con INDICE o UNICO invece della chiave primaria
WHERE dateDim = DATE('2014-04-03 00:00:00')
?
date
invece didatetime
?