0

我有以下查询:

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。

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

Just changing to InnoDB w/o explaining the underlying cause is not a particularly satisfying answer. Besides, if the solution is to just add the proper index, then that's much easier than migrating to another db engine.

I am new to relational databases. So I'm hoping that the solution is something obvious to the experts.

EDIT1:

ID is not the primary key. ChunkID is. There are approximately 40 ChunkIDs for each ID. So adding an additional ID to the table adds about 40 rows. Each unique chunk has a unique chunkHash associated with it.

EDIT2:

Here's the schema:

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    

EDIT 3:

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

编辑4:

添加 postgresql 标记以查看是否有任何 postgresql 用户可以在该 SQL 实现上获得更好的执行计划。既然如此,那我就换了。

4

3 回答 3

2

使用产生相同结果的查询进行更新。不过也不会更快。

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

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

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

于 2012-11-16T00:16:43.597 回答
2

在联接之前汇总表怎么样?

总结可能是:

 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 值才相等。

于 2012-11-16T00:20:27.753 回答
2

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

这是 PostgreSQL 查询执行计划:

在此处输入图像描述

我不再使用 MySQL。

于 2012-12-03T22:50:13.143 回答