Ich habe ein Problem mit der INDEXIERUNG einer DATETIME (oder sogar eines Datums) als ersten Teil meines PRIMARY KEY.
Ich benutze MySQL 5.5
Hier sind meine beiden Tabellen:
-- 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
Ich fülle beide Tabellen mit genau den gleichen Daten (in der Nähe von 10 000 000)
Aber:
- stats table benutze ein DATETIME für dateDim
- stats_todays verwendet un INTEGER mit TO_DAYS () für dateDim
Meine Frage ist: Warum verwendet MySQL den PRIMARY KEY nicht, wenn der erste Teil des Indexes eine Datums- / Uhrzeitangabe ist? Es ist sehr seltsam, da mit den gleichen Daten, aber mit einem INTEGER und TO_DAYS (dateDim) die gleiche Anfrage rockt ....
Beispiel mit Statistiktabelle (und Datum / Uhrzeit):
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
Gleiche Anfrage auf der anderen Tabelle stats_todays (Mit INTEGER und 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
Wenn Sie den vollständigen Beitrag lesen, verstehen Sie, dass dies kein Problem mit geringer Kardinalität ist, da die Anforderung mit genau derselben Kardinalität wie das Feld INTEGER dateDim ausgeführt wird.
Hier sind einige erweiterte Details:
SELECT COUNT( DISTINCT dateDim )
FROM stats_todays
UNION ALL
SELECT COUNT( DISTINCT dateDim )
FROM stats;
Result:
COUNT(DISTINCT dateDim)
2192
2192
Hier ist die INDEX-Beschreibung:
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
SELECT dateDim, COUNT (*) FROM Statistik GROUP BY dateDim WITH ROLLUP
- gibt an, dass es 2192 verschiedene Daten gibt und die Aufteilung reibungslos ist (ca. 3000 - 4000 Zeilen nach Datum)
- Die Tabelle enthält 8 831 990 Zeilen
- Das gleiche gilt für den anderen Tisch
- Ich habe versucht mit COVERING INDEX (* durch alle PK-Spalten ersetzen) => nichts geändert
- Ich habe versucht, force | use index => nichts zu ändern
- Dasselbe gilt für das Datumsfeld anstelle von datetime
- Dasselbe gilt für INDEX oder UNIQUE anstelle des Primärschlüssels
WHERE dateDim = DATE('2014-04-03 00:00:00')
?
date
statt verwendendatetime
?