2017-03-11 3 views
0

研究目的(サードパーティのデータ科学者コミュニティグループへのアウトソーシングなど)では、特定の機密フィールド(顧客名、電話番号、住所など)をマスクしてプロダクションデータベースをエクスポートする必要があります。dbテーブルのフィールドを匿名化および消毒する最速の方法は?

このorder_requestsテーブルのプロダクションデータベースには約5億行があるので、フィールドnicknamenickname_transformedにマスクしたいと思います。どうすれば速くできますか?

order_requestsテーブル構造:dblink

┌──────────────────┬─────────────────────────────┬────────────────────┐ 
│  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 ... 

私の現在の実装(完了するために6時間、DB上のCPUのみ< 10%一方、スタンドアロンDBのみ自分自身を使用):

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:[email protected]: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; 

一部私の考えでの質問:

  1. クローンidnicknameフィールド+空nickname_transformedフィールドだけを持つ別のテーブルを作成した場合、そこに私の操作をしてくださいコピー戻るnickname_transformed
  2. このarticleは、結果を達成するためにより複雑な方法を述べました。このための固体コードの例はありますか?

    ピュア機能/クエリです:それぞれの業務にdblink接続とリンクを管理する方法のようなもの、notifyなど

はこれを読みましたこのジョブを1〜2ヶ月ごとにやり直さなければならないので好ましい。

答えて

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; 
+0

を試してみましたこれです。クエリをありがとうが、まだ遅いです。 –

0

を:

  • 表のすべての索引を削除し、表に外部キーで必要なもののみを残します。
  • 更新を実行する - インデックスを更新する必要がないため、はるかに高速です。
  • テーブルを真空にする - 古い行のバージョンで使用されていたスペースを回収する。
  • すべてのインデックスを再作成する - これは並行して行うことができます - これにはxargs -Pを使用します。

md5(nickname)十分な匿名性を提供していません - それはいくつかのブルートフォースや虹のテーブルを検索して、元のニックネームをバック復元するために自明簡単です - 彼らは十分なエントロピーを持っていません。

あなたは、むしろsubstring(md5(nickname||'some-long-secret-string') for 8)を行う必要があります:それはすべてのニックネームをブルートフォースする機能を削除しますので

  • 秘密は、あなたの請負業者に知られていないでしょう。
  • 秘密が漏れても、切り詰められたハッシュが短すぎてニックネームを確実に元に戻すことができません。
+0

これはいくつかの必須事項を網羅していますが、完全ではありません(たとえば、使用するCPUが少なく、十分なメモリと単一の専用ホストを持っている)。 –

0

あなたは現実的なデータで作業したい場合は、https://github.com/joke2k/faker/

のようなスクリプトを使って偽のデータと実際のデータを置き換えることができます。この1はPythonであるが、同様のスクリプトは多くの言語に存在する

関連する問題