【问题标题】:How could I optimise this MySQL query?我该如何优化这个 MySQL 查询?
【发布时间】:2010-10-22 14:09:30
【问题描述】:

我有一个表,其中存储了一个学生 ID、一个类别和一个生效日期(除其他外)。日期可以是过去、现在或将来。我需要一个可以从表中提取学生当前状态的查询。

以下查询有效:

SELECT * 
FROM pupil_status 
WHERE (status_pupil_id, status_date) IN (
    SELECT status_pupil_id, MAX(status_date) 
    FROM pupil_status 
    WHERE status_date < NOW() -- to ensure we ignore the "future status"
    GROUP BY status_pupil_id );

在MySQL中,表定义如下:

CREATE TABLE IF NOT EXISTS `pupil_status` (
  `status_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `status_pupil_id` int(10) unsigned NOT NULL, -- a foreign key
  `status_category_id` int(10) unsigned NOT NULL, -- a foreign key
  `status_date` datetime NOT NULL, -- effective date/time of status change
  `status_modify` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `status_staff_id` int(10) unsigned NOT NULL, -- a foreign key
  `status_notes` text NOT NULL, -- notes detailing the reason for status change
  PRIMARY KEY (`status_id`),
  KEY `status_pupil_id` (`status_pupil_id`,`status_category_id`),
  KEY `status_pupil_id_2` (`status_pupil_id`,`status_date`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1409 ;

但是,表中有 950 名学生和超过 1400 个状态,处理查询需要 0.185 秒。现在也许可以接受,但是当表格膨胀时,我担心可伸缩性。生产系统可能会有超过 10000 名学生,每个学生都有 15-20 个状态。

有没有更好的方法来编写这个查询?我应该有更好的索引来协助查询吗?请告诉我。

【问题讨论】:

    标签: mysql optimization


    【解决方案1】:

    您可以尝试以下方法

    1 使用 INNER JOIN 而不是 WHERE

    SELECT * 
    FROM pupil_status ps
    INNER JOIN 
        (SELECT status_pupil_id, MAX(status_date) 
        FROM pupil_status 
        WHERE status_date < NOW()
        GROUP BY status_pupil_id) X
    ON ps.status_pupil_id = x.status_pupil_id
    AND ps.status_date = x.status_date
    

    2 有一个变量并存储 NOW() 的值 - 我不确定数据库引擎是否会将对 NOW() 的调用优化为一次调用,但如果没有,那么这可能会有所帮助

    这些是一些建议,但是您需要比较查询计划,看看是否有任何明显的改进。 根据您在查询计划中对索引的使用情况,上述 robob 的建议也可以派上用场

    【讨论】:

    • 谢谢!我没有意识到 WHERE...IN 和 INNER JOIN 之间会有如此惊人的差异。对于 10000 名学生的 200000 个状态,与我上面的查询相比,查询在 0.08 秒内返回,其中查询需要超过 5 分钟(然后我厌倦了等待)。不过我没有更改密钥,所以不确定是否有必要。
    【解决方案2】:

    找出当您加载系统时查询需要多长时间,该系统有 10000 个学生,每个学生有 15-20 个状态。

    仅在耗时过长时重构。

    【讨论】:

    • 似乎太明智了 ;-) 我会快速生成一些随机数据,看看会发生什么......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    相关资源
    最近更新 更多