Mysql
 sql >> Base de données >  >> RDS >> Mysql

Distance de Hamming sur des chaînes binaires en SQL

Il semble que le stockage des données dans un BINARY colonne est une approche vouée à des performances médiocres. Le seul moyen rapide d'obtenir des performances décentes est de diviser le contenu du BINARY colonne dans plusieurs BIGINT colonnes, chacune contenant une sous-chaîne de 8 octets des données d'origine.

Dans mon cas (32 octets), cela signifierait utiliser 4 BIGINT colonnes et en utilisant cette fonction :

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);

L'utilisation de cette approche, dans mes tests, est plus de 100 fois plus rapide que l'utilisation du BINARY approche.

FWIW, c'est le code auquel je faisais allusion en expliquant le problème. De meilleures façons d'accomplir la même chose sont les bienvenues (je n'aime particulièrement pas les conversions binaire> hexadécimal> décimal) :

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)
  );