我有一张包含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个查询。有没有办法优化此查询到这个程度。任何人都可以帮助实现这一结果吗?
答案 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语句以填充它结果