我在MYSQL中有两个表,其中table2包含17位数字(varchar 17)的序列号范围(唯一),table1包含序列值(格式与范围相同) 例如:
table 1:
serial_id seial
1 12345678123456799
table 2:
range id date start end
1 2012-01-01 12345678123456789 12345678123456999
2 2012-01-01 12345678123457000 12345678123457099
3 2012-01-01 12345678123457100 12345678123457199
我想找到每个序列都属于它的范围ID。可以使用的最简单的查询是:
select *
from table1,table2
where table1.serial between table2.start and table2.end
但我希望通过以下事实优化它以更快地运行: 序列号和范围是唯一的,因此每个序列可能属于一个且只有一个范围。所以当一个范围包含序列时,没有必要搜索其他范围。 每个范围的前11位数字是相同的。例如,一个范围可以是12345678120000000到12345678129999999。 连续出版物和范围按日期排序,更有可能在早期查找范围。连续出版物约有6000000条记录,范围约为100000条记录。
任何更好查询的想法?
答案 0 :(得分:0)
这对加速来说有点挑战。以下是我使用IP地址范围的一种方法:
select t1.*,
(select t2.range_id
from table2 t2
where t2.start <= t.serial
order by t2.start desc
limit 1
) as range_id
from table1 t1;
这可以利用table2(start, range_id)
上的索引。
注意:这不会检查范围的结尾。为此,我会添加另一个连接。 。 。虽然这(不幸)需要实现子查询:
select *
from (select t1.*,
(select t2.range_id
from table2 t2
where t2.start <= t.serial
order by t2.start desc
limit 1
) as range_id
from table1 t1
) t1 left join
table2 t2
on t1.range_id = t2.range_id and t2.end >= t.serial;
其他加入需要table2(range_id, end)
上的索引。
答案 1 :(得分:0)
我认为通过数据模型的一点变化,将会出现很大的性能提升。 通过将rangeid列添加到table1作为外键。
table 1:
serial_id seial rangeid
1 12345678123456799 1
然后写下面的查询:
select *
from table1 join table2 using(rangeid);
如果无法进行更改,您可以使用like运算符,如下所示:
select *
from table1 join table2
on(table2.start like concat(left(table1.serial,12),'%'))
where table1.serial between table2.start and table2.end;
table2.start列必须编入索引。
编辑: 根据序列字段和开始字段之间的关系,将数字“12”增加到最大可能数。