sql >> Base de Datos >  >> RDS >> Mysql

Distancia de Hamming en cadenas binarias en SQL

Parece que almacenar los datos en un BINARY columna es un enfoque destinado a funcionar mal. La única forma rápida de obtener un rendimiento decente es dividir el contenido de BINARY columna en múltiples BIGINT columnas, cada una de las cuales contiene una subcadena de 8 bytes de los datos originales.

En mi caso (32 bytes) esto significaría usar 4 BIGINT columnas y usando esta función:

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

Usar este enfoque, en mis pruebas, es más de 100 veces más rápido que usar BINARY acercamiento.

FWIW, este es el código que estaba insinuando al explicar el problema. Son bienvenidas mejores formas de lograr lo mismo (especialmente no me gustan las conversiones binarias> hexadecimales> decimales):

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