2017-11-02 9 views
0

私はPHP MySqlのダッシュボードで作業しています。ユーザーはログインしてダッシュボードにアクセスします。 ユーザーは単一のセクション、単一の国、複数のセクション、複数の国にアクセスできます。MySqlのクエリ最適化のアプローチ

私は3つの定義済みのビューを作成しており、定義済みのビューからは、サマリーテーブル に挿入し、ユーザーがサマリーテーブルにアクセスできるようにしています。

これらは私の定義済みのビューがあり

unit_detailsある

  select 
     sections.section_id, 
     countries.country_id, 
     business_units.unit_id, 
     sections.section_name, 
     countries.country_name, 
     cities.city_name, 
     business_units.unit_name, 
     business_unit_types.unit_type_name, 
     business_unit_categories.unit_category_name 
     from 
     sections, 
     countries, 
     cities, 
     business_units, 
     business_unit_types, 
     business_unit_categories 
     where 
      business_units.section_id=sections.section_id 
     and business_units.country_id=countries.country_id 
     and business_units.city_id=cities.city_id 
     and business_units.unit_type_id=business_unit_types.unit_type_id 
     and business_units.unit_category_id=business_unit_categories.unit_category_id 
     and cities.country_id=countries.country_id; 

TRANSACTION_DETAILS

  SELECT 
     transactions.business_date, 
     transactions.transaction_datetime, 
     business_unit_product_category_section.section_id, 
     business_units.country_id, 
     transactions.unit_id, 
     transactions.transaction_id, 
     product_category_groups.product_category_group_name, 
     transactions.product_category_id, 
     product_categories.product_category_name, 
     transactions.product_id, 
     products.product_name, 
     transactions.net_sales 
     FROM 
     transactions, 
     business_unit_product_category_section, 
     business_units, 
     products, 
     product_categories, 
     product_category_groups 
     where 
      transactions.unit_id=business_unit_product_category_section.unit_id 
     and transactions.product_category_id=business_unit_product_category_section.product_category_id 
     and transactions.unit_id=business_units.unit_id 
     and business_unit_product_category_section.section_id=business_units.section_id 
     and business_unit_product_category_section.unit_id=business_units.unit_id 
     and transactions.product_id=products.product_id 
     and transactions.product_category_id=products.product_category_id 
     and transactions.product_category_id=product_categories.product_category_id 
     and product_categories.product_category_id=products.product_category_id 
     and product_categories.product_category_group_id=product_category_groups.product_category_group_id; 

最終ビュー

  select 
     unit_details.section_name, 
     unit_details.country_name, 
     unit_details.city_name, 
     unit_details.unit_name, 
     unit_details.unit_type_name, 
     unit_details.unit_category_name, 
     transaction_details.business_date, 
     transaction_details.transaction_datetime, 
     transaction_details.section_id, 
     transaction_details.country_id, 
     transaction_details.unit_id, 
     transaction_details.transaction_id, 
     transaction_details.product_category_group_name, 
     transaction_details.product_category_id, 
     transaction_details.product_category_name, 
     transaction_details.product_id, 
     transaction_details.product_name, 
     transaction_details.net_sales 
     from unit_details ud 
     left join transaction_details td on 
     td.section_id=ud.section_id 
     and 
     td.country_id=ud.country_id 
     and 
     td.unit_id=ud.unit_id; 

これは私のサマリーテーブルクエリの1つです サマリーテーブルはSQLを実行するバッチファイルによって30分ごとに更新されます。

  SET @date_today = DATE(NOW()); 
     select 
     final_view.section_name, 
     final_view.country_name, 
     final_view.city_name, 
     final_view.unit_name, 
     final_view.unit_type_name, 
     final_view.unit_category_name, 
     sum(CASE WHEN @date_today = final_view.business_date THEN final_view.net_sales ELSE 0 END) TODAYS_NETSALES, 
     sum(CASE WHEN month(@date_today) = month(final_view.business_date) and final_view.business_date<[email protected]_today THEN final_view.net_sales ELSE 0 END) MTD_NETSALES 
     from final_view 
     group by final_view.section_name,final_view.country_name,final_view.city_name,final_view.unit_name,final_view.unit_category_name; 

これは

  CREATE TABLE business_units (
     id int(11) NOT NULL, 
     unit_id int(11) NOT NULL, 
     unit_name varchar(30) NOT NULL, 
     section_id int(11) NOT NULL, 
     country_id int(11) NOT NULL, 
     city_id int(11) NOT NULL, 
     unit_type_id int(11) NOT NULL, 
     unit_category_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE business_unit_categories (
     unit_category_id int(11) NOT NULL, 
     unit_category_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE business_unit_product_category_section (
     id int(11) NOT NULL, 
     unit_id int(11) NOT NULL, 
     product_category_id int(11) NOT NULL, 
     section_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE business_unit_types (
     unit_type_id int(11) NOT NULL, 
     unit_type_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE cities (
     city_id int(11) NOT NULL, 
     city_name varchar(30) NOT NULL, 
     country_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE countries (
     country_id int(11) NOT NULL, 
     country_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE products (
     id int(11) NOT NULL, 
     product_id varchar(13) NOT NULL, 
     product_name varchar(300) NOT NULL, 
     product_category_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE product_categories (
     product_category_id int(11) NOT NULL, 
     product_category_name varchar(30) NOT NULL, 
     product_category_group_id int(11) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE product_category_groups (
     product_category_group_id int(11) NOT NULL, 
     product_category_group_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE sections (
     section_id int(11) NOT NULL, 
     section_name varchar(30) NOT NULL, 
     created_by varchar(30) NOT NULL, 
     created_datetime datetime NOT NULL, 
     is_active_status int(1) NOT NULL COMMENT '1-active, 0-not active', 
     status_change_datetime datetime NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     CREATE TABLE transactions (
     id int(11) NOT NULL, 
     business_date date NOT NULL, 
     unit_id int(11) NOT NULL, 
     transaction_id int(11) NOT NULL, 
     transaction_datetime datetime NOT NULL, 
     product_category_id int(11) NOT NULL, 
     product_id varchar(13) NOT NULL, 
     net_sales float NOT NULL, 
     net_qty int(11) NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

     CREATE TABLE user_permissions (
     id int(11) NOT NULL, 
     user_id varchar(30) NOT NULL, 
     section_id int(11) NOT NULL, 
     country_id int(11) NOT NULL 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 


     ALTER TABLE business_units 
     ADD PRIMARY KEY (id), 
     ADD UNIQUE KEY unit_id (unit_id,section_id,country_id), 
     ADD KEY unit_id_2 (unit_id,section_id,country_id), 
     ADD KEY city_id (city_id), 
     ADD KEY unit_type_id (unit_type_id), 
     ADD KEY unit_category_id (unit_category_id); 


     ALTER TABLE business_unit_categories 
     ADD PRIMARY KEY (unit_category_id); 


     ALTER TABLE business_unit_product_category_section 
     ADD PRIMARY KEY (id), 
     ADD UNIQUE KEY unit_id (unit_id,product_category_id,section_id), 
     ADD KEY unit_id_2 (unit_id,product_category_id,section_id); 


     ALTER TABLE business_unit_types 
     ADD PRIMARY KEY (unit_type_id); 


     ALTER TABLE cities 
     ADD PRIMARY KEY (city_id), 
     ADD UNIQUE KEY city_id (city_id,country_id), 
     ADD KEY country_id (country_id), 
     ADD KEY city_id_2 (city_id,country_id); 


     ALTER TABLE countries 
     ADD PRIMARY KEY (country_id); 


     ALTER TABLE products 
     ADD PRIMARY KEY (id), 
     ADD KEY product_id (product_id), 
     ADD KEY product_category_id (product_category_id); 


     ALTER TABLE product_categories 
     ADD PRIMARY KEY (product_category_id), 
     ADD UNIQUE KEY product_category_id (product_category_id,product_category_group_id), 
     ADD KEY product_category_group_id (product_category_group_id); 


     ALTER TABLE product_category_groups 
     ADD PRIMARY KEY (product_category_group_id); 


     ALTER TABLE sections 
     ADD PRIMARY KEY (section_id); 


     ALTER TABLE transactions 
     ADD PRIMARY KEY (id), 
     ADD KEY business_date (business_date), 
     ADD KEY unit_id (unit_id), 
     ADD KEY transaction_id (transaction_id), 
     ADD KEY transaction_datetime (transaction_datetime), 
     ADD KEY product_category_id (product_category_id), 
     ADD KEY product_id (product_id), 
     ADD KEY product_id_3 (product_id,product_category_id); 


     ALTER TABLE transactions 
     MODIFY id int(11) NOT NULL AUTO_INCREMENT; 

     ALTER TABLE user_permissions 
     ADD PRIMARY KEY (id), 
     ADD UNIQUE KEY user_id_3 (user_id,section_id,country_id), 
     ADD KEY user_id (user_id), 
     ADD KEY section_id (section_id), 
     ADD KEY country_id (country_id), 
     ADD KEY user_id_2 (user_id,section_id,country_id); 

     ALTER TABLE user_permissions 
     MODIFY id int(11) NOT NULL AUTO_INCREMENT; 

私のスキーマである私の質問は、上記のような事前に定義されたビューを作成することをお勧めしているかどうか、

で、事前に定義されたビューから選択を行うと、サマリー表に挿入しますか?

事前定義されたビューとサマリーテーブルを削除してバッチを停止し、セッション中にユーザーがダッシュボードにアクセスするときにのみPHPページからサマリービューを生成する必要がありますか?

私が定義済みのビューを作成した理由は、トランザクションテーブルには何百万ものレコードがあり、サマリーテーブルを更新するのに約10-15分かかります。ユーザがダッシュボードにアクセスすると、データが利用可能となり、ユーザはデータを見るのを待つ必要がない。

セッション中にデータを生成する場合、ユーザーはデータを表示するまでに10〜15分待たなければなりません。

適切なアプローチについての親切なアドバイス、またSQLクエリを最適化するのに役立ちます。

+1

このようにクエリを作成するのを停止しました。 1992年。参加しませんか。 – Strawberry

+0

TL; DRは短期間で再現可能な問題を提出してください – DanFromGermany

+0

@DanFromGermany、問題は、セッション中にクエリを実行するとクエリに時間がかかるため、現在は30分ごとに結果を生成して保持していますユーザがログインしたときに出力が準備されます。 – davidb

答えて

1
  • あなたがここに起動し、あなたの疑問を修正(そしておそらくあなたのデータモデル)をお勧めします。
  • Unclutter - 国を正規化しないで、Cityに含めるだけです。
  • Unclutter - 本当にcreated_bycreated_datetimeが必要ですか?
  • Unclutter - 5ワードのテーブル名を使用しないでください。
  • 古い「カンマ結合」の代わりにJOIN ... ON ...を使用してください。
  • INDEX(a)INDEX(a,b)の両方を指定しないでください。前者は冗長で不要です。
  • インデックスはインデックスですので、UNIQUE(a,b)もある場合はINDEX(a,b)は不要です。戻るあなたの質問のいくつかに

...

  • VIEW(MySQLでは)シンタックスシュガーである - それは同等SELECTより短くすることはできません。 (読みやすいかもしれませんが)
  • MySQLのサマリーテーブルは明示的にサポートされていません(VIEWsでさえ)。しかし、手動で実装することはパフォーマンスのための良いアイデアです。私は時々10倍パフォーマンスの改善を参照してください。
+0

ありがとうございます。インデックス関連の疑念が解消されました。ありがとうございました。サマリー表をそのまま使用していますが、ビューから選択してサマリー表に挿入するのではなく、表から直接選択してサマリー表に挿入するだけです。 – davidb

+0

@davidb - サマリーテーブルの使用の概要です。サマリーテーブルの詳細:http://mysql.rjweb.org/doc.php/summarytables –

+0

ありがとう、これはサマリーテーブルの素晴らしい洞察でした。それは私の疑問をクリアする。 – davidb

2

答えはありません。コメントが長すぎます。

通常、このような種類のクエリをこのように記述します。私はイチゴのテキストの変更に同意する - 私はのunclutterはそれに応じて...

SELECT s.section_id 
    , c.country_id 
    , u.unit_id 
    , s.section_name 
    , c.country_name 
    , x.city_name 
    , u.unit_name 
    , t.unit_type_name 
    , y.unit_category_name 
    FROM sections s 
    JOIN business_units u 
    ON u.section_id = s.section_id 
    JOIN countries c 
    ON u.country_id = c.country_id 
    JOIN cities x 
    ON x.city_id = u.city_id 
    AND x.country_id = c.country_id -- there is a redundancy in your model here 
    JOIN business_unit_types t 
    ON t.unit_type_id = u.unit_type_id 
    JOIN business_unit_categories y 
    ON y.unit_category_id u.unit_category_id 
+0

ありがとうございます、事前定義されたビューを持つことが良いかどうかアドバイスできますか?他にも速い結果をもたらす良いアプローチがありますか? – davidb

+0

他のRDBMSにはコメントできません。 MySQLでは、インデックスを使用するビューに対するクエリの機会が非常に限られているので、ビューを使用するメリットはほとんどありません。 – Strawberry

+1

JOINSを使用した後、照会の前に 'EXPLAIN'を使用すると、調べなければならない行数とキーを使用する行数が表示されます。次に、あなたのJOINの順序を変更し、おそらく 'ORDER BY'と' LIMIT'を追加して処理を高速化することができます。また、あなたのスキームが完全に正規化されているかどうかをチェックし、データを取得しない場合は必要ない。そうすれば、多数の結果をミリ秒単位で照会することができます。 – DanFromGermany