我在MySQL(InnoDB)中有一个销售表。它的记录超过100万。我想展示一些不错的图表。获取正确的数据不是问题。快速获取它是......
所以我喜欢计算表A中每日分组的销售额(后来也是月份和年份),直到Z. Concrete;在过去的30天里,我每天都想知道我们在数据库中有多少销售记录。
所以MySQL必须返回这样的东西:
我喜欢实现MySQL返回这样的数据:
date, count
2017-04-01, 2482
2017-04-02, 1934
2017-04-03, 2701
...
销售的结构基本上是这样的:
CREATE TABLE `sales` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `contacts_created_at_index` (`created_at`),
KEY `contacts_deleted_at_index` (`deleted_at`),
KEY `ind_created_at_deleted_at` (`created_at`,`deleted_at`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
有些日子(数据点)可能没有任何结果,但我不想在数据方面存在差距。所以我也有一些日历'表
CREATE TABLE `time_dimension` (
`id` int(11) NOT NULL,
`db_date` date NOT NULL,
`year` int(11) NOT NULL,
`month` int(11) NOT NULL,
`day` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `td_ymd_idx` (`year`,`month`,`day`),
UNIQUE KEY `td_dbdate_idx` (`db_date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
每天计数30行(30天)需要30秒......
这是我尝试的第一个查询:
SELECT
`db_date` AS `date`,
(SELECT
COUNT(1)
FROM
sales
WHERE
DATE(created_at) = db_date) AS count
FROM
`time_dimension`
WHERE
`db_date` >= '2017-04-11'
AND `db_date` <= '2017-04-25'
ORDER BY `db_date` ASC
但就像我说它真的很慢(11.9秒)。我尝试了其他各种方法,但没有运气。例如:
SELECT time_dimension.db_date AS DATE,
COUNT(1) AS count
FROM sales RIGHT JOIN time_dimension ON (DATE(sales.created_at) =
time_dimension.db_date)
WHERE
(time_dimension.db_date BETWEEN '2017-03-11' AND '2017-04-11')
GROUP BY
DATE
仅1个数据点的查询只需5.4ms:
SELECT COUNT(1) FROM sales WHERE created_at BETWEEN '2017-04-11 00:00:00' AND '2017-04-25 23:59:59'
我还没有在我的本地机器上检查过innodb_buffer_poolsize。我也会检查一下。有关如何快速进行此类查询的任何想法?将来我甚至需要where子句和连接来过滤销售记录集。
感谢。
尼克
答案 0 :(得分:0)
您可以先尝试计算销售数据,然后将计数结果与日历表结合起来。
rrc3h = h2o.H2OFrame(rrc3)
答案 1 :(得分:0)
查询中有问题的部分是数据类型转换DATE(created_at)
,这有效地阻止了Mysql在created_at
使用索引。
您的1 datapoint
查询可以避免这种情况,这就是它快速运作的原因。
要解决此问题,您应该检查created_at
是否在特定日期的范围内,例如:
created_at BETWEEN db_date AND DATE_ADD(db_date,INTERVAL 1 DAY)
这样Mysql就可以根据需要使用索引(进行范围查找)。
答案 2 :(得分:0)
WHERE DATE(created_at) = db_date)
- &GT;
WHERE created_at >= db_date
AND created_at < db_date + INTERVAL 1 DAY
BETWEEN
确实如此)DATE
,DATETIME
,DATETIME(6)
created_at
隐藏在索引无法看到的函数内。对于time_dimension
,请删除PRIMARY KEY (id)
并将UNIQUE(db_date)
更改为PK。
进行这些更改后,您的原始子查询可能与LEFT JOIN ( SELECT ... )
具有竞争力。 (这取决于MySQL的版本。)