2011-01-23 10 views
22

में बाइनरी स्ट्रिंग्स पर हैमिंग दूरी मेरे पास मेरे डीबी में एक टेबल है जहां मैं एक BINARY (32) कॉलम में SHA256 हैश स्टोर करता हूं।एसक्यूएल

SELECT * FROM table 
    ORDER BY HAMMINGDISTANCE(hash, UNHEX(<insert supplied sha256 hash here>)) ASC 
    LIMIT 10 

(मामले में आप सोच रहे हैं, तार ए और बी की आलोचनात्मक अंतर: मैं एक तरह से एक की आपूर्ति की मूल्य, यानी कुछ की तरह करने के लिए स्तंभ में प्रविष्टियों की आलोचनात्मक अंतर की गणना करने के लिए देख रहा हूँ BIT_COUNT(A^B) के रूप में परिभाषित किया गया है, जहां^बिटवाई एक्सओआर ऑपरेटर है और BIT_COUNT द्विआधारी स्ट्रिंग में 1s की संख्या देता है)।

अब, मुझे पता है कि^ऑपरेटर और BIT_COUNT फ़ंक्शन केवल INTEGERs पर काम करते हैं और इसलिए मैं कहूंगा कि शायद ऐसा करने का एकमात्र तरीका सबस्ट्रिंग्स में बाइनरी स्ट्रिंग को तोड़ना होगा, प्रत्येक बाइनरी सबस्ट्रिंग को कास्ट करना होगा पूर्णांक, हथौड़ा दूरी को प्रतिस्थापित करने के लिए गणना करें और फिर उन्हें जोड़ें। इसके साथ समस्या यह है कि यह बहुत जटिल, कुशल नहीं है और निश्चित रूप से सुरुचिपूर्ण नहीं लगता है। मेरा सवाल इसलिए है: क्या आप किसी भी बेहतर तरीके से सुझाव दे सकते हैं? (कृपया ध्यान दें कि मैं साझा होस्टिंग पर हूं और इसलिए मैं डीबी सर्वर या लोड लाइब्रेरीज़ को संशोधित नहीं कर सकता)

संपादित करें (1): स्पष्ट रूप से PHP में पूरी तालिका लोड करना और गणना करना संभव होगा लेकिन मैं इसके बजाय इसे टालना क्योंकि यह तालिका शायद काफी बड़ी हो जाएगी।

संपादित करें (2): डीबी सर्वर MySQL 5.1 है

संपादित करें (3): मेरा जवाब नीचे दिए गए कोड है कि मैं सिर्फ ऊपर वर्णित हैं।

संपादित करें (4): मुझे पता चला है कि एक बिएनरी (32) के बजाय हैश को स्टोर करने के लिए 4 बिगिनट्स का उपयोग करके भारी गति सुधार (100 गुना तेजी से) उत्पन्न होता है। नीचे दिए गए मेरे उत्तर में टिप्पणियां देखें।

+0

मुक्त भी हैश स्टोर करने के लिए अलग अलग तरीके सुझाने के लिए महसूस करता है, तो यह एक खोजने में उपयोगी साबित हो सकता है बेहतर समाधान – CAFxX

+0

यदि आप हैश को 8 पूर्णांक (शायद बाइनरी स्टोरेज के अतिरिक्त) में स्टोर करेंगे, तो गणना बहुत आसान हो जाती है। – Andomar

+0

मैं वास्तव में उत्सुक हूं कि आप दूरी की गणना क्यों करना चाहते हैं :) – Nanne

उत्तर

14

में लोगों की संख्या ऐसा प्रतीत होता है से मेल खाता है प्रिंट, कि एक BINARY स्तंभ में डेटा भंडारण खराब प्रदर्शन करने के लिए एक दृष्टिकोण है। सभ्य प्रदर्शन प्राप्त करने का एकमात्र तेज़ तरीका BINARY कॉलम की सामग्री को BIGINT कॉलम में विभाजित करना है, प्रत्येक में मूल डेटा के 8-बाइट सबस्ट्रिंग हैं।

मेरे मामले (32 बाइट्स) में यह 4 BIGINT स्तंभों का उपयोग करते हैं और इस समारोह का उपयोग कर का मतलब होगा:

CREATE FUNCTION HAMMINGDISTANCE(
    A0 BIGINT, A1 BIGINT, A2 BIGINT, A3 BIGINT, 
    B0 BIGINT, B1 BIGINT, B2 BIGINT, B3 BIGINT 
) 
RETURNS INT DETERMINISTIC 
RETURN 
    BIT_COUNT(A0^B0) + 
    BIT_COUNT(A1^B1) + 
    BIT_COUNT(A2^B2) + 
    BIT_COUNT(A3^B3); 

इस दृष्टिकोण का उपयोग करना, मेरे परीक्षण में, कई बार 100 से अधिक BINARY दृष्टिकोण का उपयोग की तुलना में तेजी है।


Fwiw, इस कोड मैं जबकि समस्या को समझाने की ओर इशारा किया गया है।बेहतर तरीके इसी कार्य को पूरा करने के लिए स्वागत (मैं विशेष रूप से बाइनरी> हेक्स> दशमलव रूपांतरण पसंद नहीं है) कर रहे हैं:

CREATE FUNCTION HAMMINGDISTANCE(A BINARY(32), B BINARY(32)) 
RETURNS INT DETERMINISTIC 
RETURN 
    BIT_COUNT(
    CONV(HEX(SUBSTRING(A, 1, 8)), 16, 10)^
    CONV(HEX(SUBSTRING(B, 1, 8)), 16, 10) 
) + 
    BIT_COUNT(
    CONV(HEX(SUBSTRING(A, 9, 8)), 16, 10)^
    CONV(HEX(SUBSTRING(B, 9, 8)), 16, 10) 
) + 
    BIT_COUNT(
    CONV(HEX(SUBSTRING(A, 17, 8)), 16, 10)^
    CONV(HEX(SUBSTRING(B, 17, 8)), 16, 10) 
) + 
    BIT_COUNT(
    CONV(HEX(SUBSTRING(A, 25, 8)), 16, 10)^
    CONV(HEX(SUBSTRING(B, 25, 8)), 16, 10) 
); 
+0

मैंने अभी कुछ परीक्षण चलाए हैं: मूल प्रश्न में क्वेरी को चलाकर 100000 पंक्तियों वाली तालिका पर परिभाषित कार्य लगभग 2.5 के आसपास होता है। चूंकि मुझे वास्तव में मेरी क्वेरी के सटीक उत्तर की आवश्यकता नहीं है, इसलिए मैं एक WHERE RAND() <0.05 (तालिका के यादृच्छिक 5% का नमूना देने के लिए) जोड़कर तालिका का नमूना दे सकता हूं और यह समय को 0.2 तक नीचे लाता है । फिर भी, अगर कुछ एसक्यूएल गुरु बाहर करने के लिए एक बेहतर तरीका बता सकते हैं, तो मुझे यह सुनना अच्छा लगेगा। – CAFxX

+0

अन्य परीक्षण: मैंने एक ऐसा दृश्य बनाया जो प्रत्येक बिनरी (32) से चार बिगिनट्स को ट्रेसफॉर्म करता है। यह समय 2.5 से 0.6 के बीच कम करता है। – CAFxX

+0

ठीक है, मुझे पता चला कि अगर मैं वास्तव में एक टेबल का उपयोग करता हूं जहां मैं हैश को 4 बिगिनट्स के रूप में संग्रहीत करता हूं, तो वही क्वेरी 0.02s में पूर्ण होती है। निश्चित रूप से बिनरी (32) का उपयोग करना एक बुरा विचार (टीएम) है। – CAFxX

1

दिलचस्प सवाल है, मैं एक binary(3) कि एक binary(32) के लिए के रूप में अच्छी तरह से काम कर सकते हैं के लिए यह करने के लिए एक रास्ता मिल गया है:

drop table if exists BinaryTest; 
create table BinaryTest (hash binary(3)); 
insert BinaryTest values (0xAAAAAA); 

set @supplied = cast(0x888888 as binary); 

select length(replace(concat(
      bin(ascii(substr(hash,1,1))^ascii(substr(@supplied,1,1))), 
      bin(ascii(substr(hash,2,1))^ascii(substr(@supplied,2,1))), 
      bin(ascii(substr(hash,3,1))^ascii(substr(@supplied,3,1))) 
     ),'0','')) 
from BinaryTest; 

replace किसी भी सभी शून्यों निकाल देता है, और शेष की लंबाई है की संख्या (बाइनरी अग्रणी शून्य है, तो गिनती शून्य को छोड़ देता है के लिए रूपांतरण काम नहीं होगा।)

यह 6 जो

0xAAAAAA^0x888888 = 0x222222 = 0b1000100010001000100010