【问题标题】:MySQL filesort on GROUP BY YEAR & MonthGROUP BY YEAR & Month 上的 MySQL 文件排序
【发布时间】:2012-03-14 18:31:36
【问题描述】:

我有一个大表来存储我的网络应用程序的调试信息。问题是该表现在有 500,000 行,其中一个查询很慢,因为没有使用索引。

SQL:

EXPLAIN SELECT count(*) AS `count`, month(event_date) AS `month`, year(event_date) AS `year`FROM events WHERE 1 = 1 GROUP BY year(event_date) DESC, month(event_date) DESC LIMIT 6;

结果:

SIMPLE  events  index   NULL    event_date  8   NULL    139358  Using index; Using temporary; Using file sort

这是表结构。

CREATE TABLE IF NOT EXISTS `events` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Event Primary Key',
`event_number` int(11) NOT NULL,
`user_id` int(11) unsigned NOT NULL COMMENT 'User ID',
`server_id` int(11) unsigned DEFAULT NULL COMMENT 'The ID of the remote log client',
`remote_id` int(11) unsigned DEFAULT NULL COMMENT 'The Event Primary Key from the remote client',
`event_date` datetime NOT NULL COMMENT 'Event Datetime in local timezone',
`event_date_utc` datetime NOT NULL COMMENT 'Event Datetime in UTC timezone',
`event_type` varchar(255) NOT NULL COMMENT 'The type of event',
`event_source` varchar(255) NOT NULL COMMENT 'Text description of the source of the event',
`event_severity` varchar(255) NOT NULL COMMENT 'Notice, Warning etc',
`event_file` text NOT NULL COMMENT 'The full file location of the source of the event',
`event_file_line` int(11) NOT NULL COMMENT 'The line in the file that triggered the event',
`event_ip_address` varchar(255) NOT NULL COMMENT 'IP Address of the user that triggered the event',
`event_summary` varchar(255) NOT NULL COMMENT 'A summary of the description',
`event_description` text NOT NULL COMMENT 'Full description of the event',
`event_trace` text NOT NULL COMMENT 'Full PHP trace',
`event_synced` int(1) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY `event_type` (`event_type`),
KEY `event_source` (`event_source`),
KEY `user_id` (`user_id`),
KEY `server_id` (`server_id`),
KEY `event_date` (`event_date`)
)

如果有人对在没有文件排序的情况下获得相同结果有任何想法,那就太棒了!

【问题讨论】:

    标签: mysql indexing group-by


    【解决方案1】:

    GROUP BY 暗示 MySQL 中的 ORDER BY

    所以尝试添加 ORDER BY NULL:这通常会消除文件排序

    请参阅 MySQL 文档中的 "ORDER BY Optimization"

    【讨论】:

    • 谢谢。 ORDER BY NULL 似乎确实删除了文件排序,所以这是一个很大的改进。
    • 只是一个更新。这似乎仍然导致临时表生成结果,这意味着我的密钥缓存需要与返回的结果一样大。这加上 WHERE event_date > SUBDATE(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 6 MONTH) 有很大帮助,但它仍然没有像我希望它在当前硬件上那样快设置。再次感谢您的帮助。
    【解决方案2】:

    您的关键问题是您没有指定WHERE 子句。您对WHERE 1=1 的使用毫无意义。问题是您试图从 MySQL 获取 YEARMONTH 而不限制行数,因此它在能够处理每一行之前处理 MONTH(..) 和 YEAR(...)处理 GROUP。

    事实上,在我之前的建议表明您的查询比您透露的要多后,它仍然没有使用 INDEX,如果是这种情况,请告诉我,我可以更轻松地为您提供帮助。否则,我建议在下面进行检查(尽管我不得不猜测您的目的,因为您没有说明您要达到的目标)

    如果您是在过去 6 个日历月之后,那么以下内容也会有很大帮助。

    SELECT
        COUNT(id) AS `count`, 
        MONTH(event_date) AS `month`, 
        YEAR(event_date) AS `year`
    FROM events
    -- Get the first day of this month, and subtract 6 months
    WHERE event_date > SUBDATE(DATE_FORMAT(NOW(), '%Y-%m-01'), INTERVAL 6 MONTH)
    GROUP BY `year` DESC, `month` DESC;
    

    如果你有额外的 WHERE 标准,那会改变给出的建议,所以如果是这种情况,请更新

    【讨论】:

    • 嗨西蒙,感谢您的回复。不幸的是,这似乎根本没有提高速度。 EXPLAIN SELECT count( id ) AS count , MONTH( event_date ) AS month , YEAR( event_date ) AS year FROM EVENTS WHERE 1 =1 GROUP BY year DESC , month DESC LIMIT 6 结果:使用暂时的;使用文件排序。
    • 首先,不需要WHERE 1=1。其次,我将修改我的答案,但是您的关键问题是缺少 WHERE 来限制行数,因此它需要先查询整个数据库,然后才能对其重新排序、分组并获取前 6 行。如果您有任何 WHERE 语法(正如您继续使用 WHERE 1=1 所建议的那样),请您将其发布 - 这将使提供相关建议变得更加容易。
    • 嗨 Simon,是的,在 event_type 和 event_source 上有一些过滤(WHERE)。按照您的建议使用 SUBDATE 限制返回的行有帮助。 ORDER BY NULL 实际上似乎并没有太大帮助,我认为它确实有帮助,但是当我在更大的数据库上尝试它时仍然存在问题。基本上你的意思是我不能单独对索引进行这个查询?该表的大小约为 300 兆字节。为了提高性能,我确实需要增加 MySQL 键缓冲区缓存大小。查询很简单,这似乎有点奇怪。
    • 查询非常简单,但是所需的行数可能会变得非常大。通过限制行数,它能够立即跳过该范围之外的任何处理,从而提高性能。 ORDER BY 语法无关紧要,因为如果您不指定限制,它仍然需要处理所有行以找出最新的 6 行。
    【解决方案3】:

    除了其他人发布的内容:

    如果您运行 EXPLAIN SELECT... 并且 MySQL 报告它没有使用该查询的索引(或者不是您想要的),您可以通过使用 SELECT... FORCE INDEX... 查询数据来解决这个问题。有关此语法的更多详细信息,请查看此处:http://dev.mysql.com/doc/refman/5.6/en/index-hints.html

    【讨论】:

      【解决方案4】:
      1. 您正在使用 SELECT *,这意味着选择所有行以便扫描整个表格 - 尝试选择要显示的特定行

      2. 也没有用于过滤数据的参数,因此读取并返回整个表,尝试按日期或其他参数进行限制

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-16
        • 2018-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-09
        • 1970-01-01
        相关资源
        最近更新 更多