MySQL查询从表中获取每个条目的最新记录,包含1000万行

时间:2017-09-14 05:49:45

标签: mysql sql query-optimization greatest-n-per-group

用例:

我有桌子,让我们说:“制造商

manuf_code  manuf_display_name  record_status  record_timestamp  

----------  -------------------  ------------  ----------------
M000001      Sam                      N        2017-09-13 12:13:16      
M000002      JII                      N        2017-09-13 15:13:15      
M000002      JII                      U        2017-09-13 17:16:35      
M000003      Sun                      N        2017-09-13 18:54:16      
M000004      NG-Graphics              N        2017-09-13 19:13:15
M000004      NG-Graphics              U        2017-09-14 20:16:50 
M000004      NG-Graphics              U        2017-09-14 09:13:25 
M000005      HewNett                  N        2017-09-15 10:24:19     
M000006      HewNett                  N        2017-09-15 10:24:19  
M000007      HewNett                  N        2017-09-15 10:24:19  
M000007      HewNett                  U        2017-09-15 15:10:16 
M000007      HewNett                  U        2017-09-17 21:35:19 
M000007      HewNett                  U        2017-09-17 21:37:26  
  • 当用户创建新制造商时,详细信息位于表中, record_status 为“ N ”。
  • 当用户更新现有制造商时,该制造商ID的行将使用 record_status 更新为“ U

现在每个制造商可以有大约7-10万个这样的条目:

  • 状态为“ N
  • 的单个条目
  • 状态为“ U
  • 的多个条目

要求:我需要为每个制造商提取最新条目。

我的查询:

SELECT m.manuf_code
     , m.manuf_display_name
     , m.record_timestamp
     , m.record_status 
  FROM manufacturers m 
  JOIN
     ( SELECT manuf_code
           , MAX(record_timestamp) AS maxdate 
        FROM manufacturers 
           WHERE record_status = 'N' OR record_status = 'U' 
         GROUP 
          BY manuf_code) mn
    ON m.manuf_code = mn.manuf_code 
   AND m.record_timestamp = mn.maxdate  

我更喜欢加入子查询,因为前者更快,在获取大约7百万数据时。

但是,我需要更快地完成这项工作,因为在我获取这么多数据后,我甚至可能需要在一些表中使用新的record_status来插入相同的数据。

请建议。

编辑:

CREATE TABLE `manufacturers` (
  `manuf_code` varchar(20) NOT NULL,
  `record_status` varchar(1) NOT NULL,
  `manuf_display_name` varchar(50) NOT NULL,
  `record_timestamp` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`manuf_code`, `record_update_timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

说明:

新条目将具有状态 - > 'N' 更新现有条目将具有状态 - > 'U' 而已。查询应该是最新的。

另一个具体要求的案例是,我们获取每条记录的所有最新条目,并将状态设为“L”并再次插入

1 个答案:

答案 0 :(得分:0)

首先解决当前问题,然后讨论替代设计:

Groupwise Max

这是一个“groupwise max”问题。对于数百万行表,典型的查询相当慢,都涉及全表扫描。要改进这一点,请参阅http://mysql.rjweb.org/doc.php/groupwise_max

历史与当前

另一种方法是保留2个表:

  • History行动;这就是你现在拥有的。它主要是INSERTed进入。
  • 每个项目的
  • Current状态。这对于获取来说是微不足道的。它主要是UPDATEd。或者,更好的是,INSERT...ON DUPLICATE KEY UPDATE...以便可以插入新项目而无需额外的陈述。

您说“当用户创建/更新...”时。这是怎么进行的?我希望他们不发布SQL语句。我建议你考虑一些子程序(在客户端代码中)或存储过程(在MySQL中)。这样,您可以隐藏用户的两个表等的详细信息。

批量上传

你说大量的插入/更新/等是集体提供的吗?将此类内容加载到临时表(CREATE TEMPORARY或永久表中TRUNCATE并重用). Then write a relatively small number of SQL statements to combine the data to put into当前and shovel (mostly intact) into历史记录`。