我有一个表(变量(无限种类),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,有没有人有这方面的经验,它会对我的查询有帮助吗?
答案 0 :(得分:1)
我没有看到hadoop必然会有很大的帮助。您唯一的分区键是日期,根本问题是按天循环。 Hadoop会有所帮助,但您可以使用以下方法做得很好:
即使这可能也不是可以摧残的。如果您有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;