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

Posted

技术标签:

【中文标题】MySQL查询从具有1000万行的表中获取每个条目的最新记录【英文标题】:MySQL query for getting latest record for each entry from table with 10 million rows 【发布时间】:2018-02-22 23:41:35 【问题描述】:

用例:

我有桌子,可以说:“制造商

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  

我更喜欢 Join 子查询,因为前者更快,可以获取大约 700 万个数据。

但是,我需要更快地完成这项工作,因为在我获取这么多数据之后,我什至可能不得不在某个表中插入相同的数据并使用新的 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”并再次插入它们

【问题讨论】:

record_status 和 manuf_code 上的索引将帮助您使用相同的查询 请不要使用随机的产品和语言标签!请与您在表上的索引共享 explsin 的结果。另外,状态是否可以是 N 或 U 以外的任何值? @Shadow 对不起标签。另外,到目前为止,我还没有使用任何索引。我对使用索引不是很熟悉(如果你能指出正确的方向会很有帮助)。 您是否每次都必须选择这 700 万条记录,还是一次使用一个 manuf_code?​​span> 解释在哪里?我们还需要看SHOW CREATE TABLE厂商 【参考方案1】:

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

分组最大值

这是一个“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 intoCurrentand shovel (mostly intact) intoHistory` 的永久表中。

【讨论】:

1.保留历史记录表不是一种选择。 2.通过批量上传文件创建厂商。 (status - 'N') 3. 可以通过 UI 更新制造商,我将保存在 DB 中。(status - 'U')。 4. INSERT on DUPLICATE KEY...我建议过,但看起来我们真的需要每个制造商的信息在创建时以及如果随时更新。 我添加了关于批量上传的建议。

以上是关于MySQL查询从具有1000万行的表中获取每个条目的最新记录的主要内容,如果未能解决你的问题,请参考以下文章

具有 30M 行的表中的 COUNT(*) 和 GROUP BY

MySQL 从具有重复引用条目的联合表中选择唯一记录

如何在 SQL Server 中更新具有数百万行的大表?

从 mysql 获取大结果集

获取具有指定 id 的表中的行的值

MySQL:具有 100+ 百万行的索引表