代码之家  ›  专栏  ›  技术社区  ›  Philip

如何优化这个MySQL查询?

  •  4
  • Philip  · 技术社区  · 14 年前

    我有一张桌子,上面有学生证、分类和生效日期(除其他外)。日期可以是过去、现在或将来。我需要一个查询,从表中提取学生的当前状态。

    以下查询有效:

    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个状态。

    2 回复  |  直到 14 年前
        1
  •  4
  •   Jagmag    14 年前

    你可以试一下

    1使用内部联接而不是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()的值-我不确定DB引擎是否将这个调用优化为NOW()只是一个调用,但是如果没有,那么这可能会有点帮助

    这些是一些建议,但是您需要比较查询计划,看看是否有明显的改进。 基于您按照查询计划使用索引,robob的上述建议也可以派上用场

        2
  •  1
  •   jeffo    14 年前

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

    只有在需要太长时间时才重构。