2012-01-18 52 views
1

我需要SQL等效的this在數據庫表中查找範圍內的值

我有這樣

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並用以下

SELECT ID FROM T WHERE ? BETWEEN MN AND MX ORDER BY MN LIMIT 1 

但較弱。

+0

那麼,你可以改變'? MN和MX'到'MN> =?'之間,或者刪除'ORDER BY MN LIMIT 1'(顯然不是兩個)。但是。 。 。你當前的查詢有什麼「弱點」?不知道你對此不喜歡什麼,很難知道有什麼替代方案。 – ruakh 2012-01-18 01:17:26

+0

什麼是當前查詢時間? BETWEEN相當快。您是否在查詢中運行了'explain'來查看MySQL如何執行查詢? – 2012-01-18 01:18:46

+0

@MikePurcell - 我還沒有做到。我只是想知道是否有集體的智慧,如何做這樣的事情。 – Malvolio 2012-01-18 03:13:50

回答

0

如果在您所設定的無間隙,一個簡單的GTE比較正常:

SELECT ID FROM T WHERE ? >= MN ORDER BY MN ASC LIMIT 1 
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中;所以它仍然非常快。

+0

奇怪的是,當替換'between'時,我沒有*在掃描的行中得到同樣的下降。事實上,即使該指數似乎實際上並沒有加速(0.06到0.15秒)。桌子最終比我想象的要小得多,我認爲這只是記憶中的一切。 – Malvolio 2012-01-18 03:18:39