删除“;使用临时设备;使用filesort";从该MySQL中选择+;加入+;分组

删除“;使用临时设备;使用filesort";从该MySQL中选择+;加入+;分组,mysql,sql,postgresql,Mysql,Sql,Postgresql,我有以下疑问: select t.Chunk as LeftChunk, t.ChunkHash as LeftChunkHash, q.Chunk as RightChunk, q.ChunkHash as RightChunkHash, count(t.ChunkHash) as ChunkCount from chunks as t join chunks as q on t.ID = q.ID gr

我有以下疑问:

select 
    t.Chunk as LeftChunk,
    t.ChunkHash as LeftChunkHash,
    q.Chunk as RightChunk,
    q.ChunkHash as RightChunkHash,
    count(t.ChunkHash) as ChunkCount
from
    chunks as t
    join
    chunks as q
    on
        t.ID = q.ID
group by LeftChunkHash, RightChunkHash
下表解释如下:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  t   ALL IDIndex NULL    NULL    NULL    17796190    "Using temporary; Using filesort"
1   SIMPLE  q   ref IDIndex IDIndex 4   sotero.t.Id 12  
请注意“使用临时文件;使用文件排序”

当这个查询运行时,我很快就用完了RAM(可能是临时表的b/c),然后HDD启动,查询速度减慢到停止

我认为这可能是一个索引问题,所以我开始添加一些有意义的内容:

Table   Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Sub_part    Packed  Null    Index_type  Comment Index_comment
chunks  0   PRIMARY 1   ChunkId A   17796190    NULL    NULL        BTREE       
chunks  1   ChunkHashIndex  1   ChunkHash   A   243783  NULL    NULL        BTREE       
chunks  1   IDIndex 1   Id  A   1483015 NULL    NULL        BTREE       
chunks  1   ChunkIndex  1   Chunk   A   243783  NULL    NULL        BTREE       
chunks  1   ChunkTypeIndex  1   ChunkType   A   2   NULL    NULL        BTREE       
chunks  1   chunkHashByChunkIDIndex 1   ChunkHash   A   243783  NULL    NULL        BTREE       
chunks  1   chunkHashByChunkIDIndex 2   ChunkId A   17796190    NULL    NULL        BTREE       
chunks  1   chunkHashByChunkTypeIndex   1   ChunkHash   A   243783  NULL    NULL        BTREE       
chunks  1   chunkHashByChunkTypeIndex   2   ChunkType   A   261708  NULL    NULL        BTREE       
chunks  1   chunkHashByIDIndex  1   ChunkHash   A   243783  NULL    NULL        BTREE       
chunks  1   chunkHashByIDIndex  2   Id  A   17796190    NULL    NULL        BTREE       
但是仍然使用临时表

db引擎是MyISAM

我怎样才能摆脱使用临时的;是否在此查询中使用文件排序

仅仅更改为InnoDB而不解释根本原因并不是一个特别令人满意的答案。此外,如果解决方案只是添加适当的索引,那么这比迁移到另一个db引擎要容易得多

我不熟悉关系数据库。所以我希望解决方案对专家来说是显而易见的

编辑1:

ID不是主键。ChunkID是。每个ID大约有40个ChunkID。因此,向表中添加一个额外的ID将增加大约40行。每个唯一块都有一个与之关联的唯一chunkHash

编辑2:

以下是模式:

Field   Type    Null    Key Default Extra
ChunkId int(11) NO  PRI NULL    
ChunkHash   int(11) NO  MUL NULL    
Id  int(11) NO  MUL NULL    
Chunk   varchar(255)    NO  MUL NULL    
ChunkType   varchar(255)    NO  MUL NULL    
编辑3:

查询的最终目标是创建一个跨文档的单词共现表。chunkID是单词实例。每个实例都是一个与特定文档(ID)关联的单词。每个文件大约40个字。大约100万份文件。因此,与(显然)正在创建的完整交叉积临时表相比,生成的共现表被高度压缩。也就是说,完整的交叉积临时表是1 mil*40*40=16亿行。压缩后的结果表估计约有4000万行

编辑4:


添加postgresql标记以查看是否有任何postgresql用户可以在该SQL实现上获得更好的执行计划。如果是这种情况,我将切换。

使用生成相同结果的查询进行更新。不过不会再快了

Create Index IX_ID On Chunks (ID);

Select
  LeftChunk,
  LeftChunkHash,
  RightChunk,
  RightChunkHash,
  Sum(ChunkCount)
From (
  Select 
    t.Chunk as LeftChunk,
    t.ChunkHash as LeftChunkHash,
    q.Chunk as RightChunk,
    q.ChunkHash as RightChunkHash,
    count(t.ChunkHash) as ChunkCount
  From
    chunks as t
      inner join
    chunks as q
      on t.ID = q.ID
  Group By
    t.ID,
    t.ChunkHash,
    q.ChunkHash 
  ) x
Group By
  LeftChunk,
  LeftChunkHash,
  RightChunk,
  RightChunkHash
篡改示例测试数据

最新版本,将问题重新表述为文字和文件:

将问题重新表述为文档和单词,您有多少文档、多少单词和多少文档单词


另外,使用文档和单词的类比,您会说您的查询是“对于文档中同时出现的所有单词对,它们在任何文档中一起出现的频率是多少?”。如果单词A在一个文档中出现
n
次,单词B在同一个文档中出现
m
次,那么这将算作总数中的
n*m
次。”

使用一个生成相同结果的查询进行更新。不过不会更快

Create Index IX_ID On Chunks (ID);

Select
  LeftChunk,
  LeftChunkHash,
  RightChunk,
  RightChunkHash,
  Sum(ChunkCount)
From (
  Select 
    t.Chunk as LeftChunk,
    t.ChunkHash as LeftChunkHash,
    q.Chunk as RightChunk,
    q.ChunkHash as RightChunkHash,
    count(t.ChunkHash) as ChunkCount
  From
    chunks as t
      inner join
    chunks as q
      on t.ID = q.ID
  Group By
    t.ID,
    t.ChunkHash,
    q.ChunkHash 
  ) x
Group By
  LeftChunk,
  LeftChunkHash,
  RightChunk,
  RightChunkHash
篡改示例测试数据

最新版本,将问题重新表述为文字和文件:

将问题重新表述为文档和单词,您有多少文档、多少单词和多少文档单词


此外,使用文档和单词类比,您是否会说您的查询是“对于文档中同时出现的所有单词对,它们在任何文档中一起出现的频率是多少?”。如果单词A在文档中出现了
n
次,单词B在同一文档中出现了
m
次,那么这将计入总数中的
n*m
次。”

在联接之前汇总一下表如何

总结可能是:

 select count(*) count,
        Chunk,
        ChunkHash
   from chunks
  group by Chunk, ChunkHash
那么连接将是:

Select r.Chunk as RightChunk,
       r.ChunkHash as RightChunkHash,
       l.Chunk as LeftChunk,
       l.ChunkHash as LeftChunkHash
       sum (l.Count) + sum(r.Count) as Count
  from (
        select count(*) count,
               Chunk,
               ChunkHash
          from chunks
      group by Chunk, ChunkHash
       ) l
  join (
        select count(*) count,
               Chunk,
               ChunkHash
          from chunks
      group by Chunk, ChunkHash
       ) r on l.Chunk = r.Chunk
 group by r.Chunk, r.ChunkHash, l.Chunk, l.ChunkHash
我不确定的是你到底在数什么。所以我的SUM()+SUM()是个猜测。你可能想要SUM()*SUM()


另外,我假设两个Chunk值相等,当且仅当ChunkHash值相等。

在联接之前汇总表如何

总结可能是:

 select count(*) count,
        Chunk,
        ChunkHash
   from chunks
  group by Chunk, ChunkHash
那么连接将是:

Select r.Chunk as RightChunk,
       r.ChunkHash as RightChunkHash,
       l.Chunk as LeftChunk,
       l.ChunkHash as LeftChunkHash
       sum (l.Count) + sum(r.Count) as Count
  from (
        select count(*) count,
               Chunk,
               ChunkHash
          from chunks
      group by Chunk, ChunkHash
       ) l
  join (
        select count(*) count,
               Chunk,
               ChunkHash
          from chunks
      group by Chunk, ChunkHash
       ) r on l.Chunk = r.Chunk
 group by r.Chunk, r.ChunkHash, l.Chunk, l.ChunkHash
我不确定的是你到底在数什么。所以我的SUM()+SUM()是个猜测。你可能想要SUM()*SUM()


另外,我假设两个Chunk值相等,当且仅当ChunkHash值相等。

我从MySQL迁移到PostgreSQL,查询执行时间从~1.5天到~10分钟

以下是PostgreSQL查询执行计划:


我不再使用MySQL。

我从MySQL迁移到PostgreSQL,查询执行时间从~1.5天增加到~10分钟

以下是PostgreSQL查询执行计划:


我不再使用MySQL。

什么是表定义?ID是每个表上的主键吗?如果不是,值的分布是什么?如果ChunkHash保证是唯一的,那么计数列不总是为1吗?如果每个ID有40条记录,那么叉积(join)将爆炸到1600条加入的记录,这可能会很快增加。这就是您正在寻找的那种加入行为吗?对于临时表来说,1600是可以的。但是查询在2分钟内达到6GBs,因此我认为它正在创建一个更大的跨产品临时表。您的MySQL服务器正在按照您的要求进行操作。它在资源方面做得很正确它有。它不创建多个1600行临时表,而是创建一个肮脏的大型临时表并对其进行分类。似乎你需要一个不同的算法来实现你的目标。我认为人们可以帮助你制定一个更好的算法。但就我而言,我无法从你的查询中找出你的目标。表是什么定义?ID是每个表上的主键吗?如果不是,值的分布是什么?如果保证ChunkHash是唯一的,那么计数列不是总是为1吗?如果每个ID有40条记录,那么叉积(join)将爆炸到1600条连接记录,这可能会很快增加。这就是您正在寻找的连接行为吗?对于临时表来说,1600很好。但是查询在2分钟内达到6GBs,因此我认为它正在创建一个更大的跨产品临时表。您的MySQL服务器正在做什么