计算汉明距离的索引访问
Index Access for Calculating Hamming Distance
我有一个 table 在数据库列中填充了字符串。我正在使用绑定变量计算列的汉明距离,然后使用单独的语句输出所有字符串值,例如汉明距离小于或等于 3。
由于字符串值是绑定的,我无法在所需结果上使用虚拟列,因为据我所知,这要求函数具有静态参数。另外,我不能使用基于函数的索引,因为我的输出是派生列。
是否有替代解决方案可以在不执行完整 table 扫描的情况下优化查询?目前扫描需要 5-7 秒,我想将其减少到 300 毫秒。谢谢。
这里是部分源代码:
CREATE OR REPLACE FUNCTION HAMMING_DIS(string1 IN varchar2, string2 IN varchar2)
RETURN number IS
distance number := 0;
BEGIN
FOR counter IN 1..length(string1) LOOP
IF substr(string1, counter, 1) = substr(string2, counter, 1) THEN
distance:= distance + 1;
END IF;
END LOOP;
RETURN distance;
END;
SELECT * FROM
(SELECT FULL_NM AS FULL_NAME, HAMMING_DIS(FIRST_NM,'&A') AS HAMMING_DISTANCE
FROM STRINGS_OF_NAMES
)
WHERE HAMMING_DISTANCE > 3;
感谢您的澄清...我将删除我的其他答案。
如果……这些都是很大的假设……
- A) 你总是希望找到汉明距离小于 3 的字符串(例如,有时不小于 3 而其他时候小于 5)并且
- B) 您的 table 是 static 足以允许使用
BITMAP
索引,
那么您或许可以利用以下事实:您查询的任何答案都必须在前 4 个字符中至少有 2 个匹配项。
所以,
CREATE TABLE matt1 ( id number, str varchar(30) );
INSERT INTO matt1 SELECT rownum, dbms_random.string('U', dbms_random.value(1,30)) from dual connect by rownum <= 10000;
CREATE BITMAP INDEX i1 ON matt1 ( substr(rpad(str,4,' '),1,1) );
CREATE BITMAP INDEX i2 ON matt1 ( substr(rpad(str,4,' '),2,1) );
CREATE BITMAP INDEX i3 ON matt1 ( substr(rpad(str,4,' '),3,1) );
CREATE BITMAP INDEX i4 ON matt1 ( substr(rpad(str,4,' '),4,1) );
SELECT m.*, hamming_dis(str,:input) FROM matt1 m WHERE
(
(substr(rpad(str,4,' '),1,1) = substr(rpad(:input,4,' '),1,1) AND
substr(rpad(str,4,' '),2,1) = substr(rpad(:input,4,' '),2,1))
OR
(substr(rpad(str,4,' '),1,1) = substr(rpad(:input,4,' '),1,1) AND
substr(rpad(str,4,' '),3,1) = substr(rpad(:input,4,' '),3,1))
OR
(substr(rpad(str,4,' '),1,1) = substr(rpad(:input,4,' '),1,1) AND
substr(rpad(str,4,' '),4,1) = substr(rpad(:input,4,' '),4,1))
OR
(substr(rpad(str,4,' '),2,1) = substr(rpad(:input,4,' '),2,1) AND
substr(rpad(str,4,' '),3,1) = substr(rpad(:input,4,' '),3,1))
OR
(substr(rpad(str,4,' '),2,1) = substr(rpad(:input,4,' '),2,1) AND
substr(rpad(str,4,' '),4,1) = substr(rpad(:input,4,' '),4,1))
OR
(substr(rpad(str,4,' '),3,1) = substr(rpad(:input,4,' '),3,1) AND
substr(rpad(str,4,' '),4,1) = substr(rpad(:input,4,' '),4,1))
)
AND hamming_dis(str,:input) <= 3;
您应该会看到包含大量 BITMAP OR
和 BITMAP AND
操作的执行计划。
这可能会更快,因为您将限制实际需要计算精确汉明距离的行数。
注意:我看到您想要 <=3,而不是 <3。该方法应该可以扩展到一定程度。
我有一个 table 在数据库列中填充了字符串。我正在使用绑定变量计算列的汉明距离,然后使用单独的语句输出所有字符串值,例如汉明距离小于或等于 3。
由于字符串值是绑定的,我无法在所需结果上使用虚拟列,因为据我所知,这要求函数具有静态参数。另外,我不能使用基于函数的索引,因为我的输出是派生列。
是否有替代解决方案可以在不执行完整 table 扫描的情况下优化查询?目前扫描需要 5-7 秒,我想将其减少到 300 毫秒。谢谢。
这里是部分源代码:
CREATE OR REPLACE FUNCTION HAMMING_DIS(string1 IN varchar2, string2 IN varchar2)
RETURN number IS
distance number := 0;
BEGIN
FOR counter IN 1..length(string1) LOOP
IF substr(string1, counter, 1) = substr(string2, counter, 1) THEN
distance:= distance + 1;
END IF;
END LOOP;
RETURN distance;
END;
SELECT * FROM
(SELECT FULL_NM AS FULL_NAME, HAMMING_DIS(FIRST_NM,'&A') AS HAMMING_DISTANCE
FROM STRINGS_OF_NAMES
)
WHERE HAMMING_DISTANCE > 3;
感谢您的澄清...我将删除我的其他答案。
如果……这些都是很大的假设……
- A) 你总是希望找到汉明距离小于 3 的字符串(例如,有时不小于 3 而其他时候小于 5)并且
- B) 您的 table 是 static 足以允许使用
BITMAP
索引,
那么您或许可以利用以下事实:您查询的任何答案都必须在前 4 个字符中至少有 2 个匹配项。
所以,
CREATE TABLE matt1 ( id number, str varchar(30) );
INSERT INTO matt1 SELECT rownum, dbms_random.string('U', dbms_random.value(1,30)) from dual connect by rownum <= 10000;
CREATE BITMAP INDEX i1 ON matt1 ( substr(rpad(str,4,' '),1,1) );
CREATE BITMAP INDEX i2 ON matt1 ( substr(rpad(str,4,' '),2,1) );
CREATE BITMAP INDEX i3 ON matt1 ( substr(rpad(str,4,' '),3,1) );
CREATE BITMAP INDEX i4 ON matt1 ( substr(rpad(str,4,' '),4,1) );
SELECT m.*, hamming_dis(str,:input) FROM matt1 m WHERE
(
(substr(rpad(str,4,' '),1,1) = substr(rpad(:input,4,' '),1,1) AND
substr(rpad(str,4,' '),2,1) = substr(rpad(:input,4,' '),2,1))
OR
(substr(rpad(str,4,' '),1,1) = substr(rpad(:input,4,' '),1,1) AND
substr(rpad(str,4,' '),3,1) = substr(rpad(:input,4,' '),3,1))
OR
(substr(rpad(str,4,' '),1,1) = substr(rpad(:input,4,' '),1,1) AND
substr(rpad(str,4,' '),4,1) = substr(rpad(:input,4,' '),4,1))
OR
(substr(rpad(str,4,' '),2,1) = substr(rpad(:input,4,' '),2,1) AND
substr(rpad(str,4,' '),3,1) = substr(rpad(:input,4,' '),3,1))
OR
(substr(rpad(str,4,' '),2,1) = substr(rpad(:input,4,' '),2,1) AND
substr(rpad(str,4,' '),4,1) = substr(rpad(:input,4,' '),4,1))
OR
(substr(rpad(str,4,' '),3,1) = substr(rpad(:input,4,' '),3,1) AND
substr(rpad(str,4,' '),4,1) = substr(rpad(:input,4,' '),4,1))
)
AND hamming_dis(str,:input) <= 3;
您应该会看到包含大量 BITMAP OR
和 BITMAP AND
操作的执行计划。
这可能会更快,因为您将限制实际需要计算精确汉明距离的行数。
注意:我看到您想要 <=3,而不是 <3。该方法应该可以扩展到一定程度。