我需要等同于this的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范围完全覆盖了空间,依此类推。由于对可能的答案有所有这些限制,我应该做一些优化。不应该吗?
到目前为止,我所有人都在使用以下
索引MNSELECT ID FROM T WHERE ? BETWEEN MN AND MX ORDER BY MN LIMIT 1
但这很弱。
答案 0 :(得分:3)
如果你有一个跨越MN和MX的索引它应该非常快,即使有9M行。
alter table T add index mn_mx (mn, mx);
修改强>
我刚尝试了一个带有1M行表的测试
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 |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
值得注意的是,即使第一个explain
报告许多要扫描的行,我也有足够的innodb缓冲池设置,以便在创建后将整个内容保留在RAM中;所以它仍然很快。
答案 1 :(得分:0)
如果您的设置中没有间隙,则可以使用简单的gte比较:
SELECT ID FROM T WHERE ? >= MN ORDER BY MN ASC LIMIT 1