以下是查询:
SELECT
count(id) AS count
FROM `numbers`
GROUP BY
MONTH(created_at),
YEAR(created_at)
ORDER BY
YEAR(created_at),
MONTH(created_at)
在执行EXPLAIN时,该查询会抛出'Using temporary'和'Using filesort'。
最终我正在做的是查看用户提交的跟踪号码表,并计算按月/年分组计数的提交行数。
即。 2008年11月,提交了11,312行。
更新,这是numbers
表的DESCRIBE。
id int(11) NO PRI NULL auto_increment
tracking varchar(255) YES NULL
service varchar(255) YES NULL
notes text YES NULL
user_id int(11) YES NULL
active tinyint(1) YES 1
deleted tinyint(1) YES 0
feed text YES NULL
status varchar(255) YES NULL
created_at datetime YES NULL
updated_at datetime YES NULL
scheduled_delivery date YES NULL
carrier_service varchar(255) YES NULL
答案 0 :(得分:1)
试一试:
SELECT COUNT(x.id)
FROM (SELECT t.id,
MONTH(t.created_at) 'created_month',
YEAR(t.created_at) 'created_year'
FROM NUMBERS t) x
GROUP BY x.created_month, x.created_year
ORDER BY x.created_month, x.created_year
在WHERE
,GROUP BY
和ORDER BY
子句中使用函数不是一个好习惯,因为不能使用索引。
...查询在执行EXPLAIN时抛出'Using temporary'和'Using filesort'。
从我found开始,这是使用DISTINCT / GROUP BY时的预期结果。
答案 1 :(得分:0)
SELECT
count(`id`) AS count, MONTH(`created_at`) as month, YEAR(`created_at`) as year
FROM `numbers`
GROUP BY month, year
ORDER BY created_at
据我所知,这将是你能得到的最好的。我创建了一个带有id和datetime列的表,并用10000行填充它。上面的查询使用了一个子选择,但它实际上没有任何不同,并且具有子选择的开销。由此产生的时间为0.015秒,他的时间为0.016秒。
确保您在created_at
上有索引,这有助于初步查询。当分组出现时,很少会以文件排序结束,但在其他情况下可能会出现这种情况。如果您有这种倾向,MySql的文档会有an article。我不知道如何使用您提供的信息在这里应用这些方法。
答案 2 :(得分:0)
确保覆盖索引超过YEAR和MONTH(即同一索引中的两个字段),以便查询的ORDER BY组件可以使用索引。这应该不需要文件排序,尽管可能仍然需要临时表来处理分组。
答案 3 :(得分:0)
每当MySQL必须在内存中工作,并且该工作超过可用量(innodb_buffer_pool_size)时,它就开始使用磁盘来存储临时工作。你可以增加我提到的变量,但设置得太高可能会导致其他方面的性能问题。
如果您正在运行专用服务器,请将其设置为~50-75%。
答案 4 :(得分:0)
最好的方法是创建一个辅助列,其中包含连接在一起的YEAR
和MONTH
的数字值:
YEAR(created_at) * 100 + MONTH(created_at)
对此列进行分组将使用INDEX FOR GROUP BY
。
但是,您可以创建两个辅助表,第一个包含合理的年数(例如,从1900
到2100
),第二个包含月份(从0
到11
),并使用这些表生成集合:
SELECT (
SELECT COUNT(*)
FROM numbers
WHERE created_at >= '1900-01-01' + INTERVAL y YEAR + INTERVAL m MONTH
AND created_at < '1900-01-01' + INTERVAL y YEAR + INTERVAL m + 1 MONTH
)
FROM year_table
CROSS JOIN
month_table
WHERE y BETWEEN 2008 AND 2010
答案 5 :(得分:0)
对不起,但我不同意其他答案 我认为你需要的是为你的表添加一个索引,最好是covering index。
如果您在要搜索的列(created_at)和 上添加一个索引,您想要从(id)获得结果,那么它将比以前快得多。< / p>
您使用临时表的原因是因为您使用了分组 要加快组的速度,可以更改MySQL服务器设置以增加tmp表的大小和最大堆表大小,以便临时表位于内存中。