2011-12-09 8 views
1

私は平均で約2 - 500万行になるテーブルを持っています。それには、 'instruction_id'と呼ばれる主キー/インデックスと、 'mode'と呼ばれる別のインデックス付きフィールドがあります。今度は 'instruction_id'はプライマリキーなのでもちろんユニークですが、 'mode'は3つの異なる値のうちの1つになります。私はすべての時間を実行するクエリは、これは現在、約25秒かかります速度のためのmysqlインデックス

SELECT * FROM tablename WHERE mode = 'value1' ORDER BY instruction_id LIMIT 50 

です(> 1秒が許容できないほど長い)だけ600Kの行は今表が大きくなるにつれて、それは悪くなりますのであります。別の方法でインデックスを作成すると役立つでしょうか?もし私がindex_idとモードを一緒にインデックス付けするとそれが違いになりますか?私がどうにかしてinstruction_idで自然にテーブルを注文できるのであれば、これを別の方法で注文する必要はありませんが、どうすればいいのか分かりません。

+0

実行に時間がかかることは確かですか? 200K行を取得するには時間がかかります。特にサーバーが遠隔の場合はそうです。あなたのクエリのEXPLAIN出力を提供すると、@AdrianCornishの –

+1

も役に立ちます.LIMIT 50に注意してください。 –

+0

@ AlbinSunnanbo良い点 - ORDER BY/LIMITがMySQL自体によってストレージエンジンの外部に適用されているため、ストレージエンジンが200K行を返すことがあります。 –

答えて

5

インデックスを(mode、instruction_id)の順に試してください。

そのインデックスの背後にある理由は、それが最初にBを見つけるまでのSQL Serverモードのバイナリ検索でインデックスを検索することができますBでは、あなたはモードを検索する場合、それはこの

mode instruction_id 
A  1 
A  3 
A  4 
A  5 
A  10 
A  11 
B  2 
B  8 
B  12 
B  13 
B  14 
C  6 
C  7 
C  9 
C  15 
C  16 
C  17 

のようなインデックスを作成することです次のn行だけを出力することができます。これは本当に速く、約4M行の比較では約22です。

データの格納方法にかかわらず、結果を注文する場合は、常にORDER BYを使用してください。クエリエンジンは、PKの順序とは異なる順序で行を出力するクエリプランを選択することができます(このような単純なケースではないが、一般的に)。

+0

ありがとうございます。これはまさに私が探していたものです。 – hackartist

1

「モード」は文字フィールドですか? 3つの可能な値を保持するだけの場合は、列挙型フィールドにする必要があるように聞こえます。列挙型フィールドはテキスト文字列を返しますが、内部的に数値として格納されます。

また、Albinのインデックス作成に関するアドバイスに従うことをお勧めします。

ALTER TABLE `tablename` ADD UNIQUE (`mode`, instruction_id); 

その後:私は、サブクエリはインデックスのみを使用しなければならないよう速度のための良好な動作するようです近づい大きなテーブルのために発見した

SELECT A.* FROM tablename A JOIN (
    SELECT instruction_id FROM tablename 
    WHERE mode = 'value1' 
    ORDER BY instruction_id LIMIT 50 
    ) B 
ON (A.instruction_id = B.instruction_id); 

+0

ありがとう、良い点。残念ながら、私がそれを使用しているのはメンテナンス性が向上し、enum型の値を使用しないと変更するのが簡単ですが、余分なパフォーマンスが必要な場合はここで再度見ていきます。 – hackartist

2

は、ここでは一つの可能​​な解決策です。

> 100milレコードのテーブルで同様のクエリを使用し、結果は1〜2秒で返されます。

3

あなたはの線に沿って何か自分のスキーマを構築するとInnoDBのクラスタ化インデックスに

に関連する以下のリンクをチェックアウトする必要があります:

drop table if exists instruction_modes; 
create table instruction_modes 
(
mode_id smallint unsigned not null, 
instruction_id int unsigned not null, 
primary key (mode_id, instruction_id), -- note the clustered composite PK order ! 
unique key (instruction_id) 
) 
engine = innodb; 

コールド(mysqlの再起動)実行時のパフォーマンスは、次のように:

select count(*) from instruction_modes; 
+----------+ 
| count(*) | 
+----------+ 
| 6000000 | 
+----------+ 
1 row in set (2.54 sec) 

select distinct mode_id from instruction_modes; 
+---------+ 
| mode_id | 
+---------+ 
|  1 | 
|  2 | 
|  3 | 
+---------+ 
3 rows in set (0.06 sec) 

select * from instruction_modes where mode_id = 2 order by instruction_id limit 10; 
+---------+----------------+ 
| mode_id | instruction_id | 
+---------+----------------+ 
|  2 |    2 | 
|  2 |    3 | 
|  2 |    4 | 
|  2 |    5 | 
|  2 |    6 | 
|  2 |    9 | 
|  2 |    14 | 
|  2 |    25 | 
|  2 |    28 | 
|  2 |    32 | 
+---------+----------------+ 
10 rows in set (0.04 sec) 

0.04秒寒さはかなりパフォーマンスのようです。

希望します。

+0

ありがとうございます。私はすでにAlbin Sunnanboの答えを受けていましたが、私はこれが私が探している余分なパフォーマンスを上げるためにやることだと思っていたので、私はこれを+1しました。私は実際にすでにxaprbリンクをチェックアウトしていて、とても役に立ちました。 – hackartist

+0

+ 1のための心配と感謝はありません:) –

関連する問題