mysql - 使用哈希时获取行的单个示例的有效方法

标签 mysql sql indexing

我的数据库有一个具有以下结构的临时表:

CREATE TABLE featureMappings (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  visitId bigint(20) NOT NULL,
  featureId bigint(20) NOT NULL,
  textValue text DEFAULT NULL,
  hashTextValue char(32) GENERATED ALWAYS AS (MD5(textValue)) VIRTUAL,
  PRIMARY KEY (id));
ALTER TABLE featureMappings
ADD INDEX fsHashTextValue (featureId, hashTextValue)

在典型的运行中,该表大约有 40 - 1 亿行。有很多重复的文本值,因此我使用 hashTextValue 键能够在此列上建立索引。

以下查询运行大约需要 25 秒:

CREATE TEMPORARY TABLE temp AS
SELECT 
  featureId,
  hashTextValue
FROM 
  featureMappings
GROUP BY featureId, hashTextValue

问题

我想提取 textValue 列以及 featureIdhashTextValue 列中的值。

我尝试了两种方法。这两者都极大地增加了查询时间,因此我正在寻找更好的解决方案。

慢速选项 1 - 将 textValue 添加到查询

对查询运行 belo 更改时,处理时间从 25 秒缩短到大约 10 分钟。我试图用谷歌搜索在不使用聚合函数时如何检索 textValue ,但找不到明确的答案。

CREATE TEMPORARY TABLE temp AS
SELECT 
  featureId,
  hashTextValue,
  textValue # I also tried MIN(textValue)
FROM 
  featureMappings
GROUP BY featureId, hashTextValue

复杂选项 2:迭代更新

我的首选方法是迭代第一个查询的唯一组合,然后对以下查询运行循环:

SELECT featureId, hashTextValue INTO @fid, @htv 
FROM temp
WHERE textValue is NULL and hashTextValue IS NOT NULL
LIMIT 1;

SELECT textValue 
INTO @textValue
FROM featureMappings 
WHERE featureId = @fid and hashTextValue = @htv
LIMIT 1;

UPDATE temp
SET textValue = @textValue
WHERE featureId = @fid AND hashTextValue = @htv;

服务器配置

它正在基于 Mysql 5.7 的 AWS RDS Aurora 上运行。服务器的内存有限 (2GB),并且通常可用内存少于表上的索引大小。

最佳答案

A 计划:加载时进行重复数据删除。通过将 featureMappings 的 PK 设为 PRIMARY KEY(featureId, hashTextValue) 并在加载临时表时使用 INSERT IGNORE 即可轻松完成此操作。

B 计划:(假设有一些因素阻碍 A 计划)更改具有这些索引的表。

  PRIMARY KEY (featureId, hashTextValue, id),
  INDEX(id)

这仍然有重复,但我不清楚接下来需要发生什么。

进一步...

SELECT featureId, hashTextValue INTO @fid, @htv 
    FROM temp
    WHERE textValue is NULL and hashTextValue IS NOT NULL
    LIMIT 1;

这会带来一个问题,当你吃掉匹配的元素时,速度会变得越来越慢。最好添加显式的 PRIMARY KEY 并遍历 temp。事实上,它会快一个数量级(如果 temp 很大)。假设id是PK;那么:

SELECT @id := id, @fid := featureId, @htv := hashTextValue INTO
    FROM temp
    WHERE textValue is NULL and hashTextValue IS NOT NULL
      AND id > @id   -- this picks up 'where you left off'
    LIMIT 1;

(使用SET @id := 0;初始化)

现在您有了idUPDATE变得更简单、更快。

关于mysql - 使用哈希时获取行的单个示例的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54407340/

相关文章:

mysql - tomcat connectionpool mysql配置避免空闲连接超时

MySQL:GROUP BY 上的非聚合字段会发生什么情况?

sql - 具有大量连接的高级 SQL 查询

MySql 外键索引

mysql - 如何优化datetime条件的查询?

swift - 重新排序 UITableView 单元格并跟踪索引

php - 使用php将图片插入数据库

sql - 我的 Oracle TRIGGER 出了什么问题?

sql - LINQ to SQL 和附加子对象

mysql - 根据分组存储列的百分比