2010-10-26 6 views
14

मैं एक संपूर्ण तालिका को हैश मान में घुलन करने का एक काफी प्रभावी तरीका चाहता हूं।मैं postgresql में पूरी तालिका का हैश कैसे प्राप्त कर सकता हूं?

मैं कुछ उपकरण है कि पूरे डेटा तालिकाओं, जो तब इतने पर आगे तालिकाओं उत्पन्न करने के लिए इस्तेमाल किया जा सकता है, और उत्पन्न की है। मैं बिल्ड रनों को समन्वयित करने और काम को दोहराने से बचने के लिए एक सरल निर्माण प्रणाली को लागू करने की कोशिश कर रहा हूं। मैं इनपुट टेबल के हैंश रिकॉर्ड करने में सक्षम होना चाहता हूं ताकि मैं बाद में जांच कर सकूं कि वे बदल गए हैं या नहीं। एक टेबल बनाने में मिनट या घंटे लगते हैं, इसलिए कई सेकंड बिल्डिंग हैश खर्च करना स्वीकार्य है।

एक हैक जिसका मैंने उपयोग किया है वह सिर्फ pg_dump के आउटपुट को md5sum पर पाइप करना है, लेकिन इसके लिए नेटवर्क पर पूरे टेबल डंप को स्थानीय बॉक्स पर हैश करने के लिए उसे स्थानांतरित करने की आवश्यकता है। आदर्श रूप में मैं डेटाबेस सर्वर पर हैश का उत्पादन करना चाहता हूं।

Finding the hash value of a row in postgresql मुझे एक समय में एक पंक्ति के लिए हैश की गणना करने का एक तरीका देता है, जिसे किसी भी तरह जोड़ा जा सकता है।

किसी भी सुझाव की सराहना की जाएगी।

पोस्ट करने के लिए संपादित करें जो मैंने समाप्त किया: tinychen का जवाब सीधे मेरे लिए काम नहीं करता था, क्योंकि मैं स्पष्ट रूप से 'plpgsql' का उपयोग नहीं कर सका। जब मैंने एसक्यूएल में फ़ंक्शन को कार्यान्वित किया, तो यह काम करता था, लेकिन बड़ी टेबल के लिए बहुत अक्षम था। तो सभी पंक्तियों को जोड़कर और फिर हैशिंग करने के बजाय, मैंने "रोलिंग हैश" का उपयोग करने के लिए स्विच किया, जहां पिछले हैश को पंक्ति के पाठ प्रस्तुतिकरण के साथ संयोजित किया गया है और फिर अगले हैश का उत्पादन करने के लिए इसे धोया गया है। यह बहुत बेहतर था; स्पष्ट रूप से लाखों अतिरिक्त समय पर छोटे स्ट्रिंग्स पर एमडी 5 चलाना लाखों बार छोटे तारों को संयोजित करने से बेहतर है।

create function zz_concat(text, text) returns text as 
    'select md5($1 || $2);' language 'sql'; 

create aggregate zz_hashagg(text) (
    sfunc = zz_concat, 
    stype = text, 
    initcond = ''); 
+0

मैं यह करने के लिए किसी भी तरह से अनजान हूँ। मेरा पहला वृत्ति तालिका निर्माण को लॉग इन करना और टाइमस्टैम्प की तुलना करना होगा। – mikerobi

+1

मुझे लगता है कि आप सर्वर पर pg_dump कमांड नहीं चला सकते हैं, है ना? –

+0

@ जॉय: +1। बहुत व्यावहारिक, शायद सबसे तेज़। इसे एक उत्तर बनाओ। – Thilo

उत्तर

7

सिर्फ एक हैश तालिका एकत्रीकरण समारोह बनाने के लिए इस तरह से करते हैं।

create function pg_concat(text, text) returns text as ' 
begin 
    if $1 isnull then 
     return $2; 
    else 
     return $1 || $2; 
    end if; 
end;' language 'plpgsql'; 

create function pg_concat_fin(text) returns text as ' 
begin 
    return $1; 
end;' language 'plpgsql'; 

create aggregate pg_concat (
    basetype = text, 
    sfunc = pg_concat, 
    stype = text, 
    finalfunc = pg_concat_fin); 

तो आप तालिका के हैश मान को कम करने के लिए pg_concat फ़ंक्शन का उपयोग कर सकते हैं।

select md5(pg_concat(md5(CAST((f.*)AS text)))) from f order by id 
1

एल्गोरिथ्म के लिए के रूप में, आप सभी अलग-अलग MD5 हैश XOR सकता है, या उन्हें श्रेणीबद्ध और संयोजन हैश।

यदि आप इसे पूरी तरह से सर्वर-साइड करना चाहते हैं तो आपको शायद create your own aggregation function करना होगा, जिसे आप कॉल कर सकते हैं।

select my_table_hash(md5(CAST((f.*)AS text)) from f order by id 

एक मध्यवर्ती कदम के रूप में, बजाय ग्राहक के लिए पूरी तालिका को कॉपी करने की, तो आप सिर्फ MD5 परिणाम सभी पंक्तियों के लिए चयन करें, और md5sum के माध्यम से उन चला सकते हैं।

किसी भी तरह से आपको एक निश्चित क्रम क्रम स्थापित करने की आवश्यकता है, अन्यथा आप एक ही डेटा के लिए भी विभिन्न चेकसम के साथ समाप्त हो सकते हैं।

+0

"आपको एक निश्चित सॉर्ट ऑर्डर स्थापित करने की आवश्यकता है"। यही है कि आप हैश को दोबारा बनाना चाहते हैं। एक्सओआर के लिए यह आवश्यक नहीं है। मुझे लगता है कि एक्सओआर इतना अच्छा विचार नहीं हो सकता है। – Thilo

+1

आप सही हैं; एक्सओआर-समेकित हैश का मतलब है कि यदि आपके पास दो समान पंक्तियां हैं, और वे दोनों एक ही तरीके से बदलते हैं, तो अंतिम हैश मान मूल जैसा ही होगा। समान पंक्तियां शायद वहां नहीं होनी चाहिए, लेकिन मैं शर्त लगाता हूं कि एक्सओआर के अन्य गुण हैं जो टकराव की संभावना भी बढ़ाते हैं। – Ben

+0

सूचक के लिए धन्यवाद; मैं ऐसा करने पर एक नज़र डालेगा। दुर्भाग्यवश मैं कई अलग-अलग डीबी का उपयोग करता हूं (और नए हर समय बनाए जाते हैं), इसलिए मुझे बिल्ड सिस्टम के हिस्से के रूप में एकत्रीकरण फ़ंक्शन के निर्माण को स्क्रिप्ट करना होगा। अगर मैं कुछ और नहीं प्राप्त करता तो मैं वापस आऊंगा और इस जवाब को स्वीकार करूंगा। – Ben

16

मैं जानता हूँ कि इस पुराने सवाल है, लेकिन यह मेरा समाधान है:

SELECT   
    md5(CAST((array_agg(f.* order by id))AS text)) /* id is a primary key of table (to avoid random sorting) */ 
FROM 
    foo f; 
1

मैं एक ऐसी ही आवश्यकता थी, जब एक विशेष तालिका प्रतिकृति समाधान का परीक्षण उपयोग करने के लिए।

@ बेन के रोलिंग एमडी 5 समाधान (जिसे उन्होंने प्रश्न में जोड़ा) काफी कुशल लगता है, लेकिन कुछ जाल थे जो मुझे फिसल गए।

पहला (कुछ अन्य उत्तरों में उल्लिखित) यह है कि आपको यह सुनिश्चित करने की आवश्यकता है कि कुल तालिका उस तालिका में ज्ञात क्रम में की जाती है जिसे आप जांच रहे हैं। इसके लिए वाक्यविन्यास उदाहरण है।

select zz_hashagg(CAST((example.*)AS text) order by id) from example; 

नोट order by कुल अंदर है।

दूसरा यह है कि CAST((example.*)AS text का उपयोग उसी कॉलम सामग्री के साथ दो तालिकाओं के समान परिणाम नहीं देगा जब तक कि कॉलम उसी क्रम में बनाए गए न हों। मेरे मामले कि इसकी गारंटी नहीं किया गया था, तो एक सच्चे तुलना मैं अलग से कॉलम सूची था प्राप्त करने के लिए, उदाहरण के लिए:

select zz_hashagg(CAST((example.id, example.a, example.c)AS text) order by id) from example; 

पूर्णता के लिए (मामले में बाद में एक संपादित इसे निकाल देना चाहिए) यहाँ की परिभाषा है @ बेन सवाल से zz_hashagg:

create function zz_concat(text, text) returns text as 
    'select md5($1 || $2);' language 'sql'; 

create aggregate zz_hashagg(text) (
    sfunc = zz_concat, 
    stype = text, 
    initcond = ''); 
3
SELECT md5(array_agg(md5((t.*)::varchar))::varchar) 
    FROM (
     SELECT * 
      FROM my_table 
     ORDER BY 1 
     ) AS t 
0

महान जवाब।

किसी भी तरह कोई एकत्रीकरण कार्यों का उपयोग करने के लिए नहीं है, लेकिन तालिकाओं के लिए बनाए रखने के समर्थन कई GiB आकार, तो आप इस सबसे बड़े तालिकाओं के मामले में सबसे अच्छा जवाब से अधिक थोड़ा प्रदर्शन दंड है कि उपयोग कर सकते हैं की आवश्यकता द्वारा मामले में।

CREATE OR REPLACE FUNCTION table_md5(
    table_name CHARACTER VARYING 
    , VARIADIC order_key_columns CHARACTER VARYING []) 
RETURNS CHARACTER VARYING AS $$ 
DECLARE 
    order_key_columns_list CHARACTER VARYING; 
    query CHARACTER VARYING; 
    first BOOLEAN; 
    i SMALLINT; 
    working_cursor REFCURSOR; 
    working_row_md5 CHARACTER VARYING; 
    partial_md5_so_far CHARACTER VARYING; 
BEGIN 
    order_key_columns_list := ''; 

    first := TRUE; 
    FOR i IN 1..array_length(order_key_columns, 1) LOOP 
    IF first THEN 
     first := FALSE; 
    ELSE 
     order_key_columns_list := order_key_columns_list || ', '; 
    END IF; 
    order_key_columns_list := order_key_columns_list || order_key_columns[i]; 
    END LOOP; 

    query := (
    'SELECT ' || 
     'md5(CAST(t.* AS TEXT)) ' || 
    'FROM (' || 
     'SELECT * FROM ' || table_name || ' ' || 
     'ORDER BY ' || order_key_columns_list || 
    ') t'); 

    OPEN working_cursor FOR EXECUTE (query); 
    -- RAISE NOTICE 'opened cursor for query: ''%''', query; 

    first := TRUE; 
    LOOP 
    FETCH working_cursor INTO working_row_md5; 
    EXIT WHEN NOT FOUND; 
    IF first THEN 
     SELECT working_row_md5 INTO partial_md5_so_far; 
    ELSE 
     SELECT md5(working_row_md5 || partial_md5_so_far) 
     INTO partial_md5_so_far; 
    END IF; 
    -- RAISE NOTICE 'partial md5 so far: %', partial_md5_so_far; 
    END LOOP; 

    -- RAISE NOTICE 'final md5: %', partial_md5_so_far; 
    RETURN partial_md5_so_far :: CHARACTER VARYING; 
END; 
$$ LANGUAGE plpgsql; 

प्रयुक्त के रूप में:

SELECT table_md5(
    'table_name', 'sorting_col_0', 'sorting_col_1', ..., 'sorting_col_n' 
); 
संबंधित मुद्दे

 संबंधित मुद्दे