20,000,000表加入本身太慢了

时间:2014-08-27 20:36:16

标签: mysql sql database database-design mariadb

我有一个表(变量(无限种类),attr(正好3个不同的属性),日期,状态(只能是0,1或2)):

     PK       PK      PK
 ------------------------------------
| Variable | Attr |   Date   | State |
|------------------------------------|
|    V1    |  A1  |01/01/14  |  0    |      
|    V1    |  A1  |01/02/14  |  2    |           
|    V1    |  A1  |01/03/14  |  1    |     
|    V1    |  A1  |01/04/14  |  2    |      
|    V1    |  A2  |01/01/14  |  1    |      
|    V1    |  A2  |01/02/14  |  0    |           
|    V1    |  A2  |01/03/14  |  1    |     
|    V1    |  A2  |01/04/14  |  1    |  
|    V1    |  A3  |01/01/14  |  0    |      
|    V1    |  A3  |01/02/14  |  0    |           
|    V1    |  A3  |01/03/14  |  1    |     
|    V1    |  A3  |01/04/14  |  2    |  
|    V2    |  A1  |01/01/14  |  2    |      
|    V2    |  A1  |01/02/14  |  1    |           
|    V2    |  A1  |01/03/14  |  2    |     
|    V2    |  A1  |01/04/14  |  1    |      
|    V2    |  A2  |01/01/14  |  1    |      
|    V2    |  A2  |01/02/14  |  2    |           
|    V2    |  A2  |01/03/14  |  1    |     
|    V2    |  A2  |01/04/14  |  0    |  
|    V2    |  A3  |01/01/14  |  1    |      
|    V2    |  A3  |01/02/14  |  0    |           
|    V2    |  A3  |01/03/14  |  2    |     
|    V2    |  A3  |01/04/14  |  1    |  
|    V3    |  A1  |01/01/14  |  1    |      
|    V3    |  A1  |01/02/14  |  2    |           
|    V3    |  A1  |01/03/14  |  1    |     
|    V3    |  A1  |01/04/14  |  1    |      
|    V3    |  A2  |01/01/14  |  1    |      
|    V3    |  A2  |01/02/14  |  0    |           
|    V3    |  A2  |01/03/14  |  0    |     
|    V3    |  A2  |01/04/14  |  2    |  
|    V3    |  A3  |01/01/14  |  1    |      
|    V3    |  A3  |01/02/14  |  0    |           
|    V3    |  A3  |01/03/14  |  2    |     
|    V1    |  A3  |01/04/14  |  1    | 
|    .     |  .   |.         |  .    |
|    Vn    |  An  |n         |  n    | 
|----------|------|----------|-------|

我将运行此查询以获得我需要的结果:

select
    bases.variable as basis_v,
    bases.attr as basis_a,
    bases.state as basis_s,
    counts.variable,
    counts.attr,
    counts.state,
    count(*) as count
from 
    mytable bases
        inner join
    mytable counts
        on bases.date = counts.date
group by
    bases.variable,
    bases.attr,
    bases.state,
    counts.variable,
    counts.attr,
    counts.state
order by
    bases.variable,
    bases.attr,
    bases.state,
    counts.variable,
    counts.attr,
    counts.state;

包含约20,000,000行的表(innodb)正在加入(20,000,000 x 20,000,000)。我有一个6核Intel i7-430k,16GB ram,128GB SSD系统,这是大麦被利用。我运行此查询24小时并停止它,因为它仍未完成。我最担心的一个问题是只使用了大约1Gb的内存,而且我的CPU占用了大约10%,而我的SSD平均使用率约为1%,即使我的配置允许缓冲区访问12GB。我知道MySQL 5.6是单线程的,所以我试图进行修改。到目前为止它非常慢,我想更快地获得结果。我正在考虑使用'variable'列将表分区为16个分区。有两个索引PRIMARY =变量+ attr +日期,另一个在DATE。除了分区更改,我找不到任何其他有助于提高速度的更改,我担心单独分区不会有足够的帮助。理想情况下,我希望此查询在2-5小时内完成。有关如何提高此查询速度的任何想法都会有所帮助。除了首先只加载数据外,该表也从不用于写操作。

我要做的第一件事就是选择一个变量+ attr + state组合,我想把我的查询作为基础。所以我要说我选择V2 + A3 + 2.接下来我想去找所有行的日期,其中var = V2,attr = A3,state = 2.接下来我需要仔细检查这些日期并计算所有日期其他var + attr +状态组合。例如,如果V2 + A3 + 2发生在01/01/14,02/06 / 14,02 / 07 / 14,04 / 09/14和05/03/14,它将通过这些上的所有其他变量日期并将每个var + attr +状态组合的出现次数相加。因此输出将对每个var + attr +状态组合进行分组,并显示每个组合的计数。我提供的查询 返回我选择的变量+属性+状态组合的计数。所以这只是一个组合,但我想得到可能组合的计数(~20,000个不同的变量x 6个不同的属性x 3个不同的状态)。 JFiddle

附注:我看起来可能正在使用Hadoop这样做,但如果可以,我想坚持使用MySQL。另外,我注意到还有另一个名为MariaDB的数据库,它是一个MySQL的分支,似乎自动进行多线程,这是真的吗?这可能是一种快速解决方案吗?我已经读过关于允许使用多个内核的shard-query,有没有人有这方面的经验,它会对我的查询有帮助吗?

3 个答案:

答案 0 :(得分:1)

我没有看到hadoop必然会有很大的帮助。您唯一的分区键是日期,根本问题是按天循环。 Hadoop会有所帮助,但您可以使用以下方法做得很好:

  1. 在表格上添加日期索引;
  2. 中的数据一次一次读入您喜欢的应用程序语言(java,python,等等)。
  3. 使用嵌套循环查找应用程序中的所有对,将计数保存在某个大数组中。
  4. 重复并更新每天的计数。
  5. 即使这可能也不是可以摧残的。如果您有20,000,000行和1,000天的数据,那么每天有20,000行。这是一天20,000 * 20,000的组合。 。 。 4亿。但是,如果峰值天数为100,000,那么那天您只有10,000,000,000个组合。这是很多要处理的中间结果,无论是数据库还是hadoop。

    注意:指定问题的方式(按天相等),很难将问题并行化一天。这是可能的,但这需要更多的工作。

    编辑:

    这是寻找组合的典型问题,这是任何关联规则(又称市场购物篮分析)问题的第一步。正常的第一步是根据频率过滤可能的项目(在您的情况下是三列三联体)。因此,从查询开始:

    select cnt, count(*)
    from (select variable as basis_v, attr as basis_a, state as basis_s, count(*) as cnt
          from mytable
          group by variable, attr, state
         ) vas
    group by cnt
    order by 1 desc;
    

    这将让您了解"支持"隔断。假设它是20.然后创建一个临时表SupportItems,其中包含至少20天出现的组合。现在你的问题是找到这些组合。然后,在执行group by之前,使用此表格过滤数据中的项目。

答案 1 :(得分:0)

以下方法很棘手,但如果日期范围相对较小(60个不同的日期)并且事先知道,您可以尝试:

select v1.variable as basis_v, v1.attr as basis_a, v1.state as basis_s,
       v2.variable, v2.attr, v2.state,
       bit_count(v1.encoded_dates & v2.encoded_dates)
  from (select variable, attr, state,
               max(case when date = '2014-01-01' then 1 else 0 end) +
               max(case when date = '2014-01-02' then 2 else 0 end) +
               max(case when date = '2014-01-03' then 4 else 0 end) +
               max(case when date = '2014-01-04' then 8 else 0 end) +
               ... as encoded_dates
          from mytable
         group by variable, attr, state) v1
  join (select variable, attr, state,
               max(case when date = '2014-01-01' then 1 else 0 end) +
               max(case when date = '2014-01-02' then 2 else 0 end) +
               max(case when date = '2014-01-03' then 4 else 0 end) +
               max(case when date = '2014-01-04' then 8 else 0 end) +
               ... as encoded_dates
          from mytable
         group by variable, attr, state) v2
 where v1.encoded_dates & v2.encoded_dates > 0
 order by v1.variable, v1.attr, v1.state,
          v2.variable, v2.attr, v2.state;

它做什么?当它们出现在整数中时,它会聚合所有三元组编码日期,其中每个位代表一个日期。然后它在编码日期执行与位AND的自连接,最后对位进行计数。

我不是百分百肯定这会更有效率,但我希望预聚合会在原始表格上按日期降低昂贵的交叉加入的成本。如果可以,将内部查询提取到临时表中。

这是您的小提示,显示查询结果等同于原始查询结果:http://sqlfiddle.com/#!2/7b749/10

答案 2 :(得分:0)

尝试以下查询:

select
    bases.variable as basis_v,
    bases.attr as basis_a,
    bases.state as basis_s,
    counts.variable,
    counts.attr,
    counts.state,count(bases.variable) over(partition by     bases.attr,
    bases.state,
    counts.variable,
    counts.attr,
    counts.state)
 from 
    mytable bases
        inner join
    mytable counts
        on bases.date = counts.date
 order by
    bases.variable,
    bases.attr,
    bases.state,
    counts.variable,
    counts.attr,
    counts.state;