在具有500万行的表中最长前缀匹配的最佳MYSQL查询

时间:2013-12-20 12:28:21

标签: mysql sql

我有一张包含500万行的表

CREATE TABLE dummy_table (
            num VARCHAR(16) NOT NULL DEFAULT 0,
            rsid VARCHAR(16) NOT NULL,
            list VARCHAR(128) NOT NULL,
            PRIMARY KEY (num, rsid)
            );  
表中的

num字段是某个动态数字的前缀(上述查询中的“123457467890”)。现在我需要根据{{获取list列1}}和num以及此rsid必须是传入号码的最长前缀匹配。要获得num我有以下查询:

list

注意:123457467890`:每次投掷查询时此数字都会有所不同

现在问题是执行此查询,MYSQL大约需要0.80秒,这在我的情况下非常高。我需要在一秒钟内抛出超过1000个查询。有没有办法优化此查询到这个程度。任何人都可以帮助实现这一结果吗?

3 个答案:

答案 0 :(得分:1)

我的第一个优化是:
- 添加另一列“长度”
- 在(rsid, length DESC, num)

上添加索引

现在您的查询只是略有不同:
- SELECT list FROM dummy_table WHERE '123457467890' LIKE CONCAT(num, '%') AND rsid = '123' ORDER BY length DESC LIMIT 1;

但是,通过在索引中包含长度,查询能够在第一次匹配时停止。

然而...

这始终是一个代价高昂的过程。最糟糕的情况是您找不到匹配项 - 因此无论如何都必须扫描整套(rsid ='123')记录。

上述优化不会有助于优化最坏情况,只有最佳情况。 (匹配的时间会越长,但对于较短的匹配也无济于事。)


你可能被迫做的事情就像...... 1.创建临时表
2.将“1234567890”插入其中 3.将“123456789”插入其中 4.将“12345678”插入其中 。


ñ。将“1”插入其中

此时,您的临时表中的搜索字符串可能匹配。

然后您的查询可能会使用索引搜索。潜在地找到10个匹配(在这种情况下),然后找到最长的匹配。

-- Index now needs to be (rsid, num, length)

SELECT
  *
FROM
  dummy_table
INNER JOIN
  your_search_table
    ON dummy_table.num = your_search_table.num
WHERE
  rsid = '123'
ORDER BY
  dummy_table.length
LIMIT
  1

答案 1 :(得分:1)

无法使用索引优化测试'123457467890' like CONCAT(num, '%')。但是,它相当于:

num IN ('1', '12', '123', '1234', '12345', '123456', '1234567', '12345678', '123456789', '1234567890')

如果您在num列上有索引,可以进行优化。

如果您是从编程语言生成查询,则将其转换为此格式应该相对简单。例如,在PHP中它将是:

$nums = array();
for ($i = 1; $i <= strlen($number); $i++) {
    $nums[] = "'" . substr($number, 0, $i) . "'";
}
$where = 'num IN (' . implode(', ', $nums) . ')'

答案 2 :(得分:0)

请注意,固定长度匹配查询将使用正确的索引运行得非常快。

-- 10 number match
select list from dummy_table 
where '123457467890' = num and rsid = '123';

-- 9 number match
select list 
from dummy_table 
where '12345746789' = num and rsid = '123';

将代码包装为以传入字符串的长度开头,并在找到匹配项时停止。即使是完整的16长度字符串,也会有最多16个查询。虽然它确实执行多个查询,但它避免评估任何数据库字段,进行比最长匹配或创建中间结果集更短的任何比较。

现在每秒执行1000次查询,这取决于它们是独立的还是可以作为批处理运行,方法是加载一个额外的表,其中包含您想要的结果,并根据上述查询运行16个UPDATE语句以填充它结果