ฉันมีปัญหากับการทำดัชนีเวลา (หรือแม้กระทั่งวันที่) เป็นส่วนแรกของคีย์หลักของฉัน
ฉันใช้ MySQL 5.5
นี่คือสองตารางของฉัน:
-- 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
ฉันเติมทั้งสองตารางด้วยข้อมูลเดียวกัน (เกือบ 10,000,000)
แต่:
- ตารางสถิติใช้ DATETIME สำหรับ dateDim
- stats_todays ใช้ un INTEGER กับ TO_DAYS () สำหรับ dateDim
คำถามของฉันคือ: ทำไม MySQL ไม่ใช้คีย์หลักเมื่อส่วนแรกของดัชนีคือวันที่และเวลา ??? มันแปลกมากเนื่องจากมีข้อมูลเดียวกัน แต่รวมเข้ากับ INTEGER และ TO_DAYS (dateDim) คำขอเดียวกันนี้จะทำให้หิน ....
ตัวอย่างที่มีตารางสถิติ (และวันที่และเวลา):
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
คำขอเดียวกันบน stats_todays ตารางอื่น ๆ (ด้วย INTEGER และ 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
หากคุณอ่านโพสต์แบบเต็มคุณเข้าใจว่าไม่เป็นปัญหาเชิงการนับที่ต่ำเนื่องจากการร้องขอนั้นใช้งานได้กับ cardinality เดียวกับเขตข้อมูล INTEGER dateDim ...
นี่คือรายละเอียดขั้นสูง:
SELECT COUNT( DISTINCT dateDim )
FROM stats_todays
UNION ALL
SELECT COUNT( DISTINCT dateDim )
FROM stats;
Result:
COUNT(DISTINCT dateDim)
2192
2192
นี่คือคำอธิบาย INDEX:
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 (*) จากสถิติจัดกลุ่มตาม dateDim ด้วย ROLLUP
- บอกว่ามีวันที่แตกต่างกัน 2192 วันและการแบ่งพาร์ติชั่นนั้นราบรื่น (ประมาณ 3,000 - 4000 แถวต่อวัน)
- มี 8 831 990 แถวในตาราง
- เช่นเดียวกันสำหรับตารางอื่น ๆ
- ฉันลองด้วย COVERING INDEX (แทนที่ * ด้วยคอลัมน์ PK ทั้งหมด) => ไม่มีอะไรเปลี่ยนแปลง
- ฉันลองใช้กำลัง | use index => ไม่มีอะไรเปลี่ยนแปลง
- เขตข้อมูลเดียวกันกับวันที่แทน datetime
- เช่นเดียวกันกับ INDEX หรือ UNIQUE แทนที่จะเป็นคีย์หลัก
WHERE dateDim = DATE('2014-04-03 00:00:00')
?
date
แทนdatetime
หรือไม่?