出于研究目的(例如外包给第三方数据科学家社区组),我需要导出生产数据库,屏蔽某些敏感字段(例如客户名称,电话号码,地址等)。
现在,由于此order_requests
表上的生产数据库大约有5亿行,因此我想将字段nickname
屏蔽为nickname_transformed
。我怎么快速做到?
order_requests
表格结构:
┌──────────────────┬─────────────────────────────┬────────────────────┐
│ Column │ Type │Modifiers │
├──────────────────┼─────────────────────────────┼────────────────────┤
│ id │ integer │ not null default │
│ │ nextval('order_requests_id_seq'::regclass)│
│ vehicle_cd │ integer │ │
│ nickname │ character varying(255) │ │
│ phone_number │ character varying(255) │ │
│ pickup_time │ timestamp without time zone │ │
... 20+ fields more ...
└──────────────────┴─────────────────────────────┴────────────────────┘
Indexes:
"order_requests_pkey" PRIMARY KEY, btree (id)
... 15+ indexes more ...
Foreign-key constraints:
... 7 foreign keys ...
Referenced by:
... 25+ references more ...
我当前使用dblink
的实现(完成6个小时,而DB上的CPU仅<10%;独立的数据库仅用于我自己):
CREATE EXTENSION dblink;
ALTER TABLE
order_requests ADD nickname_transformed VARCHAR;
ALTER TABLE order_requests DISABLE TRIGGER USER;
CREATE OR REPLACE FUNCTION f_update_in_steps()
RETURNS void AS
$func$
DECLARE
_step int; -- size of step
_cur int; -- current ID (starting with minimum)
_max int; -- maximum ID
BEGIN
SELECT INTO _cur, _max min(id), max(id) FROM order_requests;
-- 100 slices (steps) hard coded
_step := ((_max - _cur) / 1000) + 1; -- rounded, possibly a bit too small
-- +1 to avoid endless loop for 0
PERFORM dblink_connect('postgres://username:password@localhost:5432/dbname'); -- your foreign server as instructed above
FOR i IN 0..2000 LOOP -- 2000 >> 1000 to make sure we exceed _max
PERFORM dblink_exec(
$$UPDATE order_requests
SET nickname_transformed = md5(nickname)
WHERE id >= $$ || _cur || $$
AND id < $$ || _cur + _step || $$
AND true$$); -- avoid empty update
_cur := _cur + _step;
EXIT WHEN _cur > _max; -- stop when done (never loop till 200)
END LOOP;
PERFORM dblink_disconnect();
END
$func$ LANGUAGE plpgsql;
我脑子里还有一些问题:
id
,nickname
字段+空nickname_transformed
字段的表格,在那里进行操作,然后复制,会更快吗?返回nickname_transformed
?dblink
连接并链接到各自的操作,notify
等读过这个:
首选纯函数/查询,因为必须每1-2个月重做一次这个工作。
答案 0 :(得分:1)
当我需要更新这么大的表中的所有行时,我使用以下过程:
xargs -P
。 md5(nickname)
没有提供足够的匿名性 - 通过一些蛮力或彩虹表搜索恢复原始昵称很容易 - 他们没有足够的熵。
你应该做substring(md5(nickname||'some-long-secret-string') for 8)
:
答案 1 :(得分:0)
为什么不:
update order_requests set nickname = id;
忘了nickname_transformed
?
如果您必须拥有nickname_transformed
,那么对于给定的nickname
,它保持相同的模糊值,那么:
create table nickname_hash (
nickname varchar(255),
hashed char(32)
);
insert into nickname_hash
select distinct nickname from order_requests;
update nickname_hash set hashed = md5(nickname);
create index idx1 on nickname_hash(nickname, hashed);
update o set
o.nickname_transformed = h.hashed
from order_requests o, nickname_hash h
where o.nickname = h.nickname;
答案 2 :(得分:0)
如果您想使用真实数据,可以使用像https://github.com/joke2k/faker/
这样的脚本将假数据替换为真实数据这个是在Python中,但类似的脚本以多种语言存在