2016-10-26 19 views
0

私には以下の要件があります。Mysqlのselect文(サブクエリ)のパフォーマンスを最適化する

create table bom_master (ID int NOT NULL AUTO_INCREMENT,label int, product varchar(20),PRIMARY KEY (ID)); 

INSERT文: -

insert into bom_master (label,product)values(1,'Budwieser'); 
insert into bom_master (label,product)values(2,'Heineken'); 
insert into bom_master (label,product)values(2,'Miller'); 
insert into bom_master (label,product)values(3,'Castle lite'); 
insert into bom_master (label,product)values(4,'Castle lager'); 
insert into bom_master (label,product)values(4,'Haywards'); 
insert into bom_master (label,product)values(3,'Kingfisher'); 
insert into bom_master (label,product)values(4,'Feni'); 

そして、これは、SELECT文の出力です。

mysql> select * from bom_master; 
+----+-------+--------------+ 
| ID | label | product  | 
+----+-------+--------------+ 
| 1 |  1 | Budwieser | 
| 2 |  2 | Heineken  | 
| 3 |  2 | Miller  | 
| 4 |  3 | Castle lite | 
| 5 |  4 | Castle lager | 
| 6 |  4 | Haywards  | 
| 7 |  3 | Kingfisher | 
| 8 |  4 | Feni   | 
+----+-------+--------------+ 
8 rows in set (0.00 sec) 

各製品のラベルを示すラベル欄があります。すぐ次のラベルは、前のラベルの子です。 ここで2は1の子、次に2は同じ1の子、3は2の子(3の直前の子)です。次に4は3の子、次に4は同じ3の子、次に3はMillerを製品として持つ2の子です。これは次のとおりです。

これを達成するには、これは私が使用しているselectステートメントです。しかし、パフォーマンスはかなり遅いです。 10000レコードの場合、フェッチするのに6〜7分かかります。しかし、50000レコードは1時間以上かかる。

mysql> select label_parent, label_child, product_parent, product_child 
    -> from (select t3.*, 
    ->    @row_num := IF(@prev_value=t3.id_child,@row_num+1,1) as rn, 
    ->    @prev_value := t3.id_child 
    ->   from (select t1.label label_parent, t2.label label_child, 
    ->      t1.product product_parent, t2.product product_child, 
    ->      t1.id id_parent, t2.id id_child 
    ->     from bom_master t1 join bom_master t2 
    ->     on  (t1.label = t2.label - 1 and t1.id < t2.id)) t3, 
    ->    (select @row_num := 1) x, 
    ->    (select @prev_value := '') y 
    ->   order by t3.id_child, t3.id_parent desc) t4 
    -> where rn = 1 
    -> order by id_child; 
+--------------+-------------+----------------+---------------+ 
| label_parent | label_child | product_parent | product_child | 
+--------------+-------------+----------------+---------------+ 
|   1 |   2 | Budwieser  | Heineken  | 
|   1 |   2 | Budwieser  | Miller  | 
|   2 |   3 | Miller   | Castle lite | 
|   3 |   4 | Castle lite | Castle lager | 
|   3 |   4 | Castle lite | Haywards  | 
|   2 |   3 | Miller   | Kingfisher | 
|   3 |   4 | Kingfisher  | Feni   | 
+--------------+-------------+----------------+---------------+ 

インデックス作成も試しました。

create index bom_master_label_id_idx on bom_master (label, id); 

パフォーマンスを向上させるにはどうすればよいですか?

+2

この1つはないので、あなたが、テーブルの構造を変更することができますあなたのケースに最適ですか? – krasipenkov

+0

どのように私はテーブルの構造を変更することができます。 ?? – user2385652

+0

私はそれを読みやすくするために答えとして追加します。 – krasipenkov

答えて

0

labelロジックを次のように変更することができます。labelをparentIdに変更します(必要ありませんが、ドキュメントの必要なしに分かりやすくなります)。 したがって、parentIdは親のIDを保持します。たとえば場合Miller氏は、ハイネケンのラベルで、ハイネケンは、あなたが持っているでしょうバドワイザーのラベルです:

+----+-------+--------------+ 
| ID | parentId | product | 
+----+-------+--------------+ 
| 1 |  0 | Budwieser | 
| 2 |  1 | Heineken  | 
| 3 |  2 | Miller  | 
+----+-------+--------------+ 

parentId = 0を持つことは、この製品は、任意の親を持っていないことを意味します。

テーブル内の製品の注文に複雑なロジックは必要ありません。

さらに最適化のために、各子製品の親へのパスを保持するpath列を追加することができます。例えば :

+----+-------+--------------+--------------+ 
| ID | parentId | product | path   | 
+----+-------+--------------+--------------+ 
| 1 |  0 | Budwieser |    | 
| 2 |  1 | Heineken  | |1|   | 
| 3 |  2 | Miller  | |2|1|  | 
+----+-------+--------------+--------------+ 
|

- はセパレータです。しかし、このpathは、insertまたはupdate製品では、コードにロジックが必要です。挿入する際には、現在の製品の親パスを取得し、親IDで追加する必要があります。

あなたがたとえばミラーを追加し、あなたが(|1|ある)ハイネケンのパスを取得し、2|でそれを追加します、その親のためのハイネケンを選択した場合(ハイネケンのID)

+0

問題は、私は選択ステートメントを変更できないということです。 select * from bom_masterは、上記と同じ結果を返します。私が提供している複雑なクエリは、クエリを2つに分割して実行することができます。 ?? – user2385652