2012-01-18 6 views
1

thisというSQLが必要です。データベーステーブルの範囲内の値を見つける

私は数を考えると、この

ID MN MX 
-- -- -- 
A 0 3 
B 4 6 
C 7 9 

のようなテーブルを持って、5を言う、私はMNおよびMXはB.になり、この場合には、その番号が含まれている行のIDを検索したい

明らか

SELECT ID FROM T WHERE ? BETWEEN MN AND MX 

はやるだろうが、私9万行を持っていると私は、これは可能な限り高速に実行したいです。特に、私はと一致することができることを知っています。これで、MN-MX範囲が完全にスペースをカバーするようになりました。可能な回答に対するこれらの制約をすべて踏まえて、私ができる最適化がいくつかあるはずです。すべきではない?

私がこれまで持っているすべては、MNのインデックスを作成し、以下の

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

を使用しますが、それは弱いです。

+0

さて、あなたは '? MNとMXを「MN> =?」に変更するか、または「MN BY LIMIT 1」を削除します(明らかに両方ではありません)。しかし、。 。 。現在のクエリについて「弱い」とは何ですか?あなたが嫌い​​なことを知らずに、どのような選択肢を提案するのかを知るのは難しいです。 – ruakh

+0

現在のクエリ時間はどのくらいですか? BETWEENはかなり高速です。クエリで 'explain'を実行して、MySQLがクエリを実行する方法の内訳を確認しましたか? –

+0

@MikePurcell - 私はまだそれをしていない。そんなことをする方法について集団的な知恵があったのかどうか疑問に思っていただけです。 – Malvolio

答えて

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列テーブル/ Wテストを試み

編集

私はMN値のインクリメントの範囲を有し、その後にMX設定私の例で
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) 

+ 3それは私が1以上を持っている理由ですが、同じものをあなたに適用する必要があります。

編集2クエリを再加工

は間違いなくそれは最初explain多く以上の行は、私は十分にInnoDBのバッファプールのセットを持っていた、スキャンすることが報告さにもかかわらず、注目に値します

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 | 
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+ 

良くなりますそれを作成した後にすべてのものをRAMに保存する。それはまだかなり速かったです。

+0

不思議なことに、「間」を置き換えたときにスキャンされた行で、同じドロップオフを取得しませんでした。実際、インデックスでさえ、実際にはそれほど高速化していないようです(0.06〜0.15秒の間)。テーブルは私が予想していたよりずっと小さくなってしまった。私はそれがちょうどすべての記憶にあると思う。 – Malvolio

関連する問題