我正在使用Idempotence来确保同一条消息不会多次保存到数据库中。为了确保这一点,我需要3列的组合。我不是在一个可能为null的3列上建立索引,而是进行计算和Digest并将其存储在索引且唯一的列上。
我现在需要将此计算应用于之前的所有消息,其中有数百万行。
Message.rb:
def set_unique_identifier
part_one = mm_id || SecureRandom.uuid
part_two = c_id
part_three = s_id
self.unique_identifier = Digest::SHA1.hexdigest("#{part_one}-#{part_two}-#{part_three}")
end
然后我有这样的迁移:
Message.find_each.with_index do |message, index|
message.set_unique_identifier
message.save
puts "SETTING UNIQUE IDENTIFIER FOR #{index}" if index % 1000 == 0
end
然而,显然,这需要很长时间才能计算出来。有没有更快的方法来使用原始SQL?
答案 0 :(得分:2)
无论具有一百万行的解决方案,您都将涉及一定程度的计算。你可以做的是减少数据的移动。 Postgresql的加密模块支持SHA1散列和UUID生成。
使用那些可以使用的逻辑保留服务器中的逻辑并将其作为单个SQL语句执行,或者如果您想以块的形式执行多个语句。
UPDATE message SET unique_identifier = encode(digest(
mm_id || gen_random_uuid() || '-' || c_id || '-' || s_id
,'sha1'),'hex');
但是,您正在做的事情实际上并未检查唯一性,因为随机组件意味着可以允许具有相同mm_id,c_id,s_id的两条消息。
您最好使用唯一的数据库约束。您可以在原始列上创建唯一索引。
CREATE UNIQUE INDEX ON message(mm_id,c_id,s_id);
并依靠postgres来处理这个问题。这是我首先要做的事情,不要担心性能问题,直到您以这种方式尝试并且可以衡量性能。
另一种方法是在函数上创建索引。它将以大致相同的方式运作:
CREATE UNIQUE INDEX ON message (encode(digest(mm_id || c_id || s_id,'sha1'),'hex'));