6

我有一个表,其主键为字符串,如12a4..., c3af...。我想并行处理它们:

process_them(1,4) on machine 1
process_them(2,4) on machine 2
process_them(3,4) on machine 3
process_them(4,4) on machine 4

执行上述操作必须选择表中的所有行,而不需要机器相互协调。我能想到的最好的主意是将它们分成 16 个,例如:

select * from table where id like '1%'
...
select * from table where id like 'e%'
select * from table where id like 'f%'

有没有更好的主意可以让我进行更多拆分,例如总行的 1/2、1/4、1/8、1/16、1/32 等?

注意:我这样做是为了对用户数据进行夜间处理并向他们发送通知。我没有在数据库本身上编辑任何东西。而且我们需要一次处理数千个用户,它不能以细粒度的方式进行拆分,因为那样不会有效率。

4

2 回答 2

2

好主意...

您可以使用 MD5 散列以合理分布的方式快速、一致地(永远不会丢失行)并且无需 ddl 更改来分布行。

*let n = number of desired partitions. Use the following sql to 
*let s = salt, expirementally chosen to provide the best distribution based on key allocation pattern.
SELECT *  FROM TABLE WHERE mod( cast( conv( md5( concat( s, Priamry_Key ) ), 16, 10), n ) = 0; 
SELECT *  FROM TABLE WHERE mod( cast( conv( md5( concat( s, Priamry_Key ) ), 16, 10), n ) = 1; 
...
...
SELECT *  FROM TABLE WHERE mod( cast( conv( md5( concat( s, Priamry_Key ) ), 16, 10), n ) = (n-1);

这是我在生产环境中多次看到的一种方法,效果很好。

这里的 SQL 没有经过测试,我没有对 sytax 做任何保证。

于 2013-08-01T18:01:01.560 回答
0

最简单的方法是status在表中添加一列,至少有两种状态:

0 = pending
1 = *not* pending

然后每个处理线程将能够“保留”一小批行来处理它们。一般的工作流程是:

BEGIN TRANSACTION;
SELECT * FROM queue WHERE status = 0 LIMIT 5 FOR UPDATE; -- load 5 pending items
-- if no pending item: terminate here
-- save this list of jobs in your application layer here
UPDATE queue SET status = 1 WHERE id IN (@id_list); -- list of id's from the previous step
COMMIT;
-- process your jobs here
-- loop

根据您的工作的实际处理时间,这种方法的开销可能太大而无法令人满意。LIMIT在第一步中增加,以便一次加载更多作业,以降低相对开销,但代价是跨进程的作业分布可能不太平衡。

于 2013-08-01T14:36:00.603 回答