Mysql 在数据库表中查找范围内的值
我需要的SQL等效于 我有一张这样的桌子Mysql 在数据库表中查找范围内的值,mysql,Mysql,我需要的SQL等效于 我有一张这样的桌子 ID MN MX -- -- -- A 0 3 B 4 6 C 7 9 给定一个数字,比如说5,我想找到MN和MX包含该数字的行的ID,在本例中是B 显然, SELECT ID FROM T WHERE ? BETWEEN MN AND MX 可以,但我有900万行,我希望它运行得尽可能快。特别是,我知道只能有一个匹配行,我现在知道MN-MX范围完全覆盖了空间,等等。有了所有这些对可能答案的限制,我应该可以做一些优化。不应该有吗 到目前为
ID MN MX
-- -- --
A 0 3
B 4 6
C 7 9
给定一个数字,比如说5,我想找到MN和MX包含该数字的行的ID,在本例中是B
显然,
SELECT ID FROM T WHERE ? BETWEEN MN AND MX
可以,但我有900万行,我希望它运行得尽可能快。特别是,我知道只能有一个匹配行,我现在知道MN-MX范围完全覆盖了空间,等等。有了所有这些对可能答案的限制,我应该可以做一些优化。不应该有吗
到目前为止,我所拥有的只是索引MN并使用以下内容
SELECT ID FROM T WHERE ? BETWEEN MN AND MX ORDER BY MN LIMIT 1
但这是很弱的。如果您的集合中没有空白,那么简单的gte比较就可以了:
SELECT ID FROM T WHERE ? >= MN ORDER BY MN ASC LIMIT 1
如果您有一个跨越MN和MX的索引,它应该非常快,即使有9M行
alter table T add index mn_mx (mn, mx);
编辑
我刚试过一个测试,有一个1米长的表格
mysql> select count(*) from T;
+----------+
| count(*) |
+----------+
| 1000001 |
+----------+
1 row in set (0.17 sec)
mysql> show create table T\G
*************************** 1. row ***************************
Table: T
Create Table: CREATE TABLE `T` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`mn` int(10) DEFAULT NULL,
`mx` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `mn_mx` (`mn`,`mx`)
) ENGINE=InnoDB AUTO_INCREMENT=1048561 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> select * from T order by rand() limit 1;
+--------+-----------+-----------+
| id | mn | mx |
+--------+-----------+-----------+
| 112940 | 948004986 | 948004989 |
+--------+-----------+-----------+
1 row in set (0.65 sec)
mysql> explain select id from T where 948004987 between mn and mx;
+----+-------------+-------+-------+---------------+-------+---------+------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+--------+--------------------------+
| 1 | SIMPLE | T | range | mn_mx | mn_mx | 5 | NULL | 239000 | Using where; Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+--------+--------------------------+
1 row in set (0.00 sec)
mysql> select id from T where 948004987 between mn and mx;
+--------+
| id |
+--------+
| 112938 |
| 112939 |
| 112940 |
| 112941 |
+--------+
4 rows in set (0.03 sec)
在我的例子中,我只是有一个mn值的递增范围,然后将mx设置为+3,这就是为什么我得到了大于1的值,但应该对您应用相同的值
编辑2
修改您的查询肯定会更好
mysql> explain select id from T where mn<=947892055 and mx>=947892055;
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | T | range | mn_mx | mn_mx | 5 | NULL | 9 | Using where; Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
mysql>解释从T选择id,其中mn=947892055;
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
|id |选择|类型|类型|可能的|键|键|列|参考|行|额外|
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
|1 |简单| T |范围| mn|uMX | mn|uMX | 5 |空| 9 |使用where;使用索引|
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
值得注意的是,尽管第一个
explain
报告了更多要扫描的行,但我已经设置了足够的innodb缓冲池,以便在创建之后将整个内容保存在RAM中;所以还是很快。好吧,你可以改变?在MN和MX之间
到MN>=?
,或者按MN限制1删除订单(但显然不是两者都有)。但是您当前的查询有什么“薄弱”之处?如果不知道你不喜欢什么,就很难知道该建议什么替代方案。目前的查询时间是多少?两者之间的距离相当快。您是否对您的查询运行了explain
,以查看MySQL将如何执行查询的详细信息?@MikePurcell-我还没有这样做。我只是想知道在如何做这样的事情上是否有集体智慧。奇怪的是,在替换
之间的时,我没有在扫描的行中得到相同的下降。事实上,即使是索引似乎也没有实际加速多少(在0.06到0.15秒之间)。桌子最终比我预想的要小得多,我想这一切都在记忆中。