这是我的表:
CREATE TABLE `tab_adasf` (
`adasf_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`adasf_shopId` int(10) unsigned NOT NULL,
`adasf_localId` bigint(20) unsigned NOT NULL,
`adasf_shopState` varchar(255) DEFAULT NULL,
`adasf_shopCity` varchar(255) DEFAULT NULL,
`adasf_shopName` varchar(255) DEFAULT NULL,
`adasf_shopDoor` varchar(255) DEFAULT NULL,
`adasf_computerName` varchar(255) DEFAULT NULL,
`adasf_channel` bigint(20) NOT NULL,
`adasf_totalInside` bigint(20) NOT NULL,
`adasf_totalOutside` bigint(20) NOT NULL,
`adasf_createdAt` datetime NOT NULL,
PRIMARY KEY (`adasf_id`),
KEY `adasf_shopId` (`adasf_shopId`),
KEY `adasf_localId` (`adasf_localId`),
KEY `adasf_shopState` (`adasf_shopState`,`adasf_shopCity`,`adasf_shopName`,`adasf_shopDoor`),
KEY `adasf_computerName` (`adasf_computerName`,`adasf_channel`,`adasf_createdAt`),
CONSTRAINT `tab_adasf_ibfk_1` FOREIGN KEY (`adasf_shopId`) REFERENCES `tab_shop` (`shop_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1453500 DEFAULT CHARSET=utf8
正如AUTO_INCREMENT的值所示:它有1453500行。
为了生成XML文件,我需要结果集如下:
SELECT
UPPER(adasf_shopState) AS adasf_shopState,
UPPER(adasf_shopCity) AS adasf_shopCity,
UPPER(adasf_shopName) AS adasf_shopName,
UPPER(adasf_shopDoor) AS adasf_shopDoor,
adasf_computerName,
adasf_channel,
SUM(adasf_totalInside) AS adasf_totalInside,
SUM(adasf_totalOutside) AS adasf_totalOutside,
YEAR(adasf_createdAt) AS year,
MONTH(adasf_createdAt) AS month,
DAY(adasf_createdAt) AS day,
HOUR(adasf_createdAt) AS hour
FROM tab_adasf
WHERE 1=1 AND adasf_shopId = '1' AND HOUR(adasf_createdAt) BETWEEN '10:00' AND '21:00'
GROUP BY
UPPER(adasf_shopState),
UPPER(adasf_shopCity),
UPPER(adasf_shopName),
UPPER(adasf_shopDoor),
adasf_computerName,
adasf_channel,
YEAR(adasf_createdAt),
MONTH(adasf_createdAt),
DAY(adasf_createdAt),
HOUR(adasf_createdAt)
ORDER BY
UPPER(adasf_shopState),
UPPER(adasf_shopCity),
UPPER(adasf_shopName),
UPPER(adasf_shopDoor),
UPPER(adasf_computerName),
adasf_channel,
adasf_createdAt
运行和获取需要3分钟。
我的问题是:我做错了什么?如何加快查询或表格的速度?
提前致谢!
答案 0 :(得分:2)
要加快查询速度,您可以在tab_adasf(adasf_shopId)
上创建索引。如果你有很多商店,这应该有助于提高性能。
如果您需要执行此类型的大量查询,请考虑将adasf_createdAt
列拆分为日期组件和时间组件。然后,您可以在tab_adasf(adasf_shopId, adasf_createdAt_time)
上创建索引,进一步帮助查询。
除非您有充分的理由,否则建议不要将时间与日期时间分开。提高此类查询的性能是一个“好理由”。
答案 1 :(得分:1)
正如其他人所说的那样,报告整个表的这样的查询本来就非常耗时。话虽如此,这里有一两个建议。
首先,消除UPPER()
子句中的GROUP BY
函数调用。无论如何,MySQL的排序规则都不区分大小写。
其次,而不是GROUP BY
年,月,日,小时,尝试在GROUP BY中使用此表达式。
DATE_FORMAT(adasf_createdAt, '%Y-%m-%d %H:00:00')
这基本上将您的createdAt
值四舍五入到前一个小时。
第三,让我们重构一下WHERE
项目
HOUR(adasf_createdAt) BETWEEN '10:00' AND '21:00'
应该说
HOUR(adasf_createdAt) BETWEEN 10 AND 21
如果您从主查询中删除它,它将加快速度。然后,您可以将查询包装在另一个查询中,如下所示:
SELECT *
FROM ( /*your whole query without the WHERE HOUR() BETWEEN clause */
) AS q
WHERE q.hour BETWEEN 10 AND 21
最后,尝试在
上创建覆盖索引的化合物 adasf_shopId, adasf_shopState, adasf_shopCity, adasf_shopName, adasf_shopDoor,
adasf_computerName, adasf_channel, adasf_CreatedAt,
adasf_totalInside, adasf_totalOutside
此索引包含按顺序排列的满足查询所需的所有信息。这可能会加快您的查询速度。
因此,您的最终查询如下所示:
SELECT *
FROM (
SELECT
UPPER(adasf_shopState) AS adasf_shopState,
UPPER(adasf_shopCity) AS adasf_shopCity,
UPPER(adasf_shopName) AS adasf_shopName,
UPPER(adasf_shopDoor) AS adasf_shopDoor,
adasf_computerName,
adasf_channel,
SUM(adasf_totalInside) AS adasf_totalInside,
SUM(adasf_totalOutside) AS adasf_totalOutside,
YEAR(adasf_createdAt) AS year,
MONTH(adasf_createdAt) AS month,
DAY(adasf_createdAt) AS day,
HOUR(adasf_createdAt) AS hour
FROM tab_adasf
WHERE 1=1
AND adasf_shopId = '1'
GROUP BY
adasf_shopState,
adasf_shopCity,
adasf_shopName,
adasf_shopDoor,
adasf_computerName,
adasf_channel,
DATE_FORMAT(adasf_createdAt, '%Y-%m-%d %H:00:00')
ORDER BY
adasf_shopState,
adasf_shopCity,
adasf_shopName,
adasf_shopDoor,
adasf_computerName,
adasf_channel,
DATE_FORMAT(adasf_createdAt, '%Y-%m-%d %H:00:00')
) AS q
WHERE q.hour BETWEEN 10 AND 21
您的查询简化以及覆盖索引可以使查询更快。
请注意,我还没有调试此查询,也没有测试数据。
答案 2 :(得分:-1)
编辑:这个答案在MySQL中不起作用。
您必须使用全表扫描检查每一行,看它是否与HOUR(adasf_createdAt) BETWEEN '10:00' AND '21:00'
匹配。
在HOUR(adasf_createdAt)
上创建功能索引。
另外,请参阅http://use-the-index-luke.com以获取有关如何有效使用索引的优秀教程。