2017-01-24 10 views
2

上位n個の行を選択しますだから私は、長い数百万行、おそらく、テーブルを持っている効率的

user | points 
--------------- 
user1 | 10 
user2 | 12 
user3 | 7 
... 

SELECT * FROM mytable ORDER BY points LIMIT 100, 1000 にしたい今では正常に動作しますが、それは拒否しているので、(巨大なテーブル上)恐ろしく遅いです任意の種類の索引を使用できますが、全表スキャンを実行します。これをより効率的にするにはどうすればいいですか?

私の最初の(わかりやすい)アイデアはpoints DESCのインデックスを使用していましたが、MySQLがそれらをまったくサポートしていないことが分かりました。それは

最後のソートにインデックスを使用doesntのため、

次に、私は、どちらか、基本的にポイント超の上昇率を有する意味、ポイントの記号を逆にするこのdidntはヘルプを試してみました、私はforce indexを使用してみました、このまだテーブル全体をフェッチしているので、ほとんどのパフォーマンスの改善は得られませんでした(ファイル番号:EXPLAINでfilesort:falseを使用)

私はこの問題を解決する必要がありますが、オンラインで役立つ情報は見つかりませんでした。どんなヒントも大歓迎です。

+0

テーブル内に「何百万もの行」がある場合は、実行しているハードウェア用のデータベースが大きすぎることがあります。しかし、構造そのものは、それに関連しています。あなたのデータベースは単にユーザー/ポイントですか?のように、主キーはvarcharですか?または? – Eoghan

+2

これはどのように「トップn」ですか? – Strawberry

+0

@Strawberry MySqlが 'top n'をサポートしているとは思いませんか? –

答えて

1

クエリからパフォーマンスを向上させる方法はいくつかあります。

never never use SELECT *それはルーキーミスです。基本的には、クエリプランナにすべてを与える必要があることを伝えます。 常には、結果セットで必要な列を列挙します。これはあなたが望むクエリーです(あなたの質問をあまり単純化していないと仮定します)。

SELECT user, points 
    FROM table 
    ORDER BY points 
    LIMIT 100,1000 

複合インデックスを使用してください。クエリの場合、複合インデックス(points, user)は、部分的なインデックススキャンを使用してクエリを満たすことができます。それは完全なテーブルソートよりも速くなければなりません。 MySQLはインデックスを前後にスキャンすることができるので、降順を心配する必要はありません。

このようなコマンドを使用するには、次のようにします。

ALTER TABLE table ADD INDEX points_user (points, user); 

を編集します。 SELECT *の使用に対する示唆は、(1)問題のテーブルが過度に単純化され、実生活に他の列があるという私の未確認の疑念、および(2)インデックスがクエリを正確に照合して最良になるという不都合な現実パフォーマンス結果。

私は経験に基づいて、パフォーマンスの感度を持つクエリでSELECT *を使用することは、(何度も何度も何度も何度もやり直したいという質問が好きでない限り)優れたエンジニアリングプラクティスではないと考えています。

+2

"基本的には、クエリプランナにすべてを渡す必要があることを伝えます。" --- *すべて*何?プランナーは2つの列があることを確かに知っているので、クエリはクエリオプティマイザがどのように見えるかという点で同じです。 – zerkms

+0

@zerkmsそれは私の思考の訓練でもありましたが、明らかに違いがあります。それにもかかわらず、複合インデックスを使用して私の問題を解決したようです! – CBenni

+0

@CBenniそれはそれを助けるインデックスをカバーするMySQLのですか?私は 'SELECT *'と 'SELECT user、points'はこの特定のケースで何かを変えるとは信じられません。 – zerkms