【发布时间】:2014-10-29 12:25:52
【问题描述】:
我有一个名为 DATA_TIMESLOTS 的表,其中包含近 150 万行。 表格是这样制作的:
+-------+---------------+-----------+
| ID | SRV_TIMESTAMP | DEVICE_ID |
+-------+---------------+-----------+
| 134322| 1414583866 | A1323 |
| 134323| 1414583832 | B1423 |
| 134324| 1414583876 | A1323 |
| 134325| 1414583883 | B1423 |
| 134326| 1414583896 | A1323 |
| 134327| 1414583964 | C1524 |
| 134328| 1414581065 | A1323 |
| .... | ........ | ..... |
+-------+---------------+-----------+
ID 是增量 PK,SRV_TIMESTAMP 和 DEVICE_ID 形成集群主键(因为不同的 device_id 可能具有相同的 srv_timestamp) 另一个名为 DATA_RAW 的表也包含近 150 万行。表格是这样制作的:
+--------------+---------+---------+---------+---------+
| TIMESLOT_ID | POWER#1 | POWER#2 | POWER#3 | POWER#4 |
+--------------+---------+---------+---------+---------+
| 134322| 342532 | 354365 | 643654 | 77687 |
| 134323| 439642 | 269436 | 363466 | 16436 |
| 134324| 436252 | 326436 | 643645 | 31616 |
| 134325| 564326 | 867867 | 176471 | 16466 |
| 134326| 148585 | 643633 | 754277 | 43643 |
| 134327| 345298 | 754765 | 626364 | 32632 |
| 134328| 324898 | 532575 | 634366 | 65436 |
| .... | .. | .. | .. | .. |
+--------------+---------+---------+---------+---------+
显然 TIMESLOT_ID 是该表的 PK。 如您所见,TIMESLOT_ID 是第一个表的外键。 现在我需要获取每天的统计数据如下:
SELECT
T.DEVICE_ID AS DEVICE_ID,
DAY(T.SRV_TIMESTAMP) AS SRV_DAY,
MONTH(T.SRV_TIMESTAMP) AS SRV_MONTH,
YEAR(T.SRV_TIMESTAMP) AS SRV_YEAR,
SUM(D.POWER#1) AS DAY_POWER#1,
SUM(D.POWER#2) AS DAY_POWER#2,
SUM(D.POWER#3) AS DAY_POWER#3,
SUM(D.POWER#4) AS DAY_POWER#4
FROM DATA_RAW AS D
INNER JOIN DATA_TIMESLOTS AS T ON T.ID=D.TIMESLOT_ID
GROUP BY
T.DEVICE_ID,
YEAR(T.SRV_TIMESTAMP),
MONTH(T.SRV_TIMESTAMP),
DAY(T.SRV_TIMESTAMP)
查询运行良好,但速度非常慢(在 64 位 4 CPU / 4GB 机器上运行 1,5M 条记录大约需要 60 秒)。我怀疑尽管我在 DATA_TIMESLOTS 表中的 DEVICE_ID、SRV_TIMESTAMP 字段上放置了索引,但这些索引是无效的,因为 DAY()、MONTH()、YEAR() 函数。所以我尝试改用 DATE() 函数,但结果是一样的。所以问题是:我是否必须在 DATA_TIMESLOT 表中为 Day、Month、Year 添加其他字段,在它们上放置适当的索引并浪费一些空间以提高性能,或者还有另一种方法可以在不浪费空间的情况下获得这个结果?
好吧,我已经在 My SQLSERVER Express 2005 (Microsoft) 上进行了一些测试,我不得不承认上述问题已经完全解决。已确认在对键或索引应用函数后,MySQL 无法保留键或索引。恕我直言,这是一个非常严重的限制。 解决方案似乎是: 1) 为天、月、年添加 3 个附加字段 2)索引这些字段 3)在这些领域进行分组 另一方面,我正在认真考虑删除 Timestamp 字段的可能性,因为在那之后完全没用。我学到的教训是,在 MySQL Timestamp 类型中永远不应该用作键或索引,因为当您对其应用函数(例如日、月、小时、年等)时,索引将失效......
【问题讨论】:
-
你能准备一个这样的 sqlfiddle 吗?
-
需要相当多的空间来通过上传 150 万行来复制问题...没有意义。
-
它确实可以查看架构(表和索引),显然上传所有数据没有意义。还显示带有
explain的查询计划会很有用
标签: mysql performance indexing group-by timestamp