将十六进制索引拆分为n个部分

时间:2013-08-01 05:51:00

标签: mysql

我的表格中包含字符串中的主键,例如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等?

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

2 个答案:

答案 0 :(得分: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上没有任何关于gaurantee的问题。

答案 1 :(得分: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以便一次加载更多作业,以降低相对开销,代价是跨过程可能不太平衡的作业传播。