2016-04-08 15 views
0

node_id、user_id、rht、lft、値の列を持つ1つのMySQLテーブルに、複数のMPTT(Modified Preorder Travelsal Trees)を保存します。単一ツリーは、Webサイト上の1人のユーザーに割り当てられます。私が使用するユーザーのために指定されたノードからツリーを選択するにはネストされたクエリを使用してMySQLのSELECTパフォーマンスを向上させる

SELECT * FROM categories 
WHERE user_id = 123 
AND lft > node_lft 
AND rht < node_rht; 

私はこの機能のためにネストされたクエリを使用して考える:

で動作しているときに高速であるクエリの
SELECT t.* FROM 
(SELECT * FROM categories WHERE user_id = 123) t 
WHERE lft > node_lft 
AND rht < node_rht; 

大規模なデータ(例えば10000人のユーザー、誰もがランダムな深さと要素の数を持つ単一のツリーを持っています)、なぜですか?

答えて

2

本当に良い理由がない限り、MySQLのFROM句にネストされたサブクエリを使用しないでください。 MySQLはこのようなサブクエリを実現します。オーバーヘッドに加えて、ジョイン用の索引の使用も防ぎます。

代わりに、テーブルに正しいインデックスを定義するだけです。あなたのクエリに基づいて:

categories(user_id, lft, rht) 
0

いずれかのクエリはどちらのクエリにも役立ちます。 SHOW CREATE TABLEを入力してください。サブクエリなし

INDEX(user_id, lft)(またはINDEX(user_id, rht))はuser_id=123行のおそらく半分をスキャンします。単純にINDEX(user_id)以上の小さな改善。 'range'()、(user_id, lft, rht)のため、3列のインデックスはlftの範囲を超えます。従って有益ではない。サブクエリで

  1. user_id=123を持つすべての行を抽出します。 tmpテーブルに入れます。
  2. そのtmpテーブルをスキャンします。索引は役に立ちません。

サブクエリは高速化できません。そうであれば、タイミングテストを実行したときにキャッシュされた内容に違いがあった可能性があります。

テーブルの大きさはどれくらいですか?どのくらいの大きさのキャッシュ(InnoDBならinnodb_buffer_pool_size)?テーブルが大きすぎると、「レイジールックアップ」が保証されます。

何かのためにnode_idを使用していますか?このコンボはユニークですか:(user_id, lft, rht);もしそうなら、それはPRIMARY KEYかもしれません。 (PKを介したアクセスは通常、InnoDBのセカンダリキーより高速です)

関連する問題