繁体   English   中英

删除“使用临时; 使用MySQL的select + join + group by中的“使用文件排序”

[英]Removing “Using temporary; Using filesort” from this MySQL select+join+group by

我有以下查询:

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       

但是仍然使用临时表。

数据库引擎是MyISAM。

我如何摆脱使用临时文件; 在此查询中使用文件排序?

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

我是关系数据库的新手。 因此,我希望解决方案对专家而言是显而易见的。

编辑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万* 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

摆弄示例测试数据http://sqlfiddle.com/#!3/ea1a5/2

最新的提琴,将问题改写为单词和文档: http : //sqlfiddle.com/#!3/f5aef/12

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

另外,使用文档和单词的比喻,您是否要说的查询是“对于同时出现在文档中的所有单词对,它们在任何文档中一起出现的频率。如果单词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()。

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

我从MySQL迁移到PostgreSQL,查询执行时间从〜1.5天缩短到〜10分钟。

这是PostgreSQL查询执行计划:

在此处输入图片说明

我不再使用MySQL。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM