2017-01-13 20 views
-1

私はここに最小限のビュー内の4つのテーブルがあります。MySQLのサブクエリの最適化

販売:

id 
has_discount 
discount_is_percentage 
discount_amount 
**sale_date_time** 
**order_status** 

Sales_items:

id 
**sales_id** 
has_discount 
discount_is_percentage 
discount_amount 
**product_id** (This can sometimes be null) 
price_inc_vat_per_item 
quantity 
vat_rate 
is_removed 

Sales_payments:

id 
**sales_id** 
payment_amount 
payment_change 
payment_method 

製品:

id 
product_name 

私はその場で割引を計算して報告するクエリを持っています。これはレコードの総数が100〜200kを下回った場合に効果的です。しかし、数が増えるにつれて、かかる時間は本当に遅くなります。私は使用しているサブクエリのためだと思います。誰でもこの光を放つことができます。各表には、システム内の他のユーザーと区別するためのclient_idおよびoutlet_idがあります。

現在、テーブルには1〜3百万行があり、問題のクライアントには300k〜600kがあります。クエリには30秒以上かかります。ローの量が少ない他の人には、サブ秒ですら取得できます。星付きのものが指標です。同じ結果を得るためにクエリをどのように改善できますか?私が今持っているクエリ:

SELECT DATE_FORMAT(CONVERT_TZ(sales.sale_date_time,'UTC','Europe/London'), 
       '%l%p') as title, count(*) as total_sales, SUM(sales_items.quantity 
        ) as total_quantities, 
     SUM(sales_items.price_before_line_discount) as price_before_line_discount, 
     SUM(sales_items.price_before_line_discount-sales_items.line_discount) as price_after_line_discount, 
     SUM(sales_items.vat_rated_sales) as vat_rated_sales_before_discount, 
     SUM(sales_items.zero_rated_sales) as zero_rated_sales_before_discount, 
     SUM(sales_items.total_vat_only) as total_vat_only_before_discount, 
     SUM(sales_payments.payment_taken) as payment_taken, SUM(sales_items.line_discount) as total_line_discount, 
     SUM(sales_payments.payment_cash) as payment_cash, SUM(CASE WHEN sales.has_discount=1 
       AND sales.discount_is_percentage=0 THEN sales.discount_amount WHEN sales.has_discount=1 
       AND sales.discount_is_percentage=1 THEN ((sales_items.price_before_line_discount-sales_items.line_discount)*sales.discount_amount/100) WHEN sales.has_discount=0 THEN 0 END 
      )as total_sales_discount, 
     SUM(CASE WHEN sales.has_discount=1 THEN CASE WHEN discount_is_percentage=0 THEN (sales_items.vat_rated_sales*sales.discount_amount)/(sales_items.price_before_line_discount-sales_items.line_discount) WHEN discount_is_percentage=1 THEN (sales_items.vat_rated_sales*((sales_items.price_before_line_discount-sales_items.line_discount)*sales.discount_amount/100))/(sales_items.price_before_line_discount-sales_items.line_discount) END ELSE 0 END)as vat_rated_sales_discount, 
     SUM(CASE WHEN sales.has_discount=1 THEN CASE WHEN discount_is_percentage=0 THEN (sales_items.zero_rated_sales*sales.discount_amount)/(sales_items.price_before_line_discount-sales_items.line_discount) WHEN discount_is_percentage=1 THEN ((sales_items.zero_rated_sales*((sales_items.price_before_line_discount-sales_items.line_discount)*sales.discount_amount/100))/(sales_items.price_before_line_discount-sales_items.line_discount)) END ELSE 0 END)as zero_rated_sales_discount, 
     SUM(CASE WHEN sales.has_discount=1 THEN CASE WHEN discount_is_percentage=0 THEN (sales_items.total_vat_only*sales.discount_amount)/(sales_items.price_before_line_discount-sales_items.line_discount) WHEN discount_is_percentage=1 THEN (sales_items.total_vat_only*((sales_items.price_before_line_discount-sales_items.line_discount)*sales.discount_amount/100))/(sales_items.price_before_line_discount-sales_items.line_discount) END ELSE 0 END)as total_vat_only_discount 
    FROM `sales` 
    left join 
    (
     SELECT sales_id, SUM(quantity) as quantity, SUM(price_inc_vat_per_item*quantity) AS price_before_line_discount, 
       SUM(CASE WHEN has_discount=1 
         AND discount_is_percentage=0 THEN discount_amount WHEN has_discount=1 
         AND discount_is_percentage=1 THEN ((price_inc_vat_per_item*quantity)*discount_amount/100) WHEN has_discount=0 THEN 0 END 
        )as line_discount, 
       SUM(CASE WHEN vat_rate>0 THEN CASE WHEN has_discount=1 
         AND discount_is_percentage=0 THEN ((price_inc_vat_per_item*quantity)-discount_amount) WHEN has_discount=1 
         AND discount_is_percentage=1 THEN ((price_inc_vat_per_item*quantity)-((price_inc_vat_per_item*quantity)*discount_amount/100)) WHEN has_discount=0 THEN (price_inc_vat_per_item*quantity) END ELSE 0 END 
        )as vat_rated_sales, 
       SUM(CASE WHEN vat_rate=0 THEN CASE WHEN has_discount=1 
         AND discount_is_percentage=0 THEN ((price_inc_vat_per_item*quantity)-discount_amount) WHEN has_discount=1 
         AND discount_is_percentage=1 THEN ((price_inc_vat_per_item*quantity)-((price_inc_vat_per_item*quantity)*discount_amount/100)) WHEN has_discount=0 THEN (price_inc_vat_per_item*quantity) END ELSE 0 END 
        )as zero_rated_sales, 
       SUM(CASE WHEN vat_rate>0 THEN CASE WHEN has_discount=1 
         AND discount_is_percentage=0 THEN ((price_inc_vat_per_item*quantity)-discount_amount)-((price_inc_vat_per_item*quantity)-discount_amount)/(1+(vat_rate/100)) WHEN has_discount=1 
         AND discount_is_percentage=1 THEN ((price_inc_vat_per_item*quantity)-((price_inc_vat_per_item*quantity)*discount_amount/100))-((price_inc_vat_per_item*quantity)-((price_inc_vat_per_item*quantity)*discount_amount/100))/(1+(vat_rate/100)) WHEN has_discount=0 THEN (price_inc_vat_per_item*quantity)-(price_inc_vat_per_item*quantity)/(1+(vat_rate/100)) END ELSE 0 END 
        )as total_vat_only 
      FROM sales_items 
      WHERE client_id='0fe26d93-775f-440c-a119-13cbcb6cbc0c' 
       AND is_removed=0 
      GROUP BY sales_id 
    ) as sales_items ON `sales`.`id` = `sales_items`.`sales_id` 
    left join 
    (
     SELECT sales_id, SUM(payment_amount-payment_change) payment_taken, 
       SUM(CASE WHEN payment_method='CASH' THEN (payment_amount-payment_change) ELSE 0 END) as payment_cash 
      FROM sales_payments 
      WHERE client_id='0fe26d93-775f-440c-a119-1396c36cbc0c' 
      GROUP BY sales_id 
    ) as sales_payments ON `sales`.`id` = `sales_payments`.`sales_id` 
    WHERE `sales`.`client_id` = '0fe26d93-775f-440c-a119-1396c36cbc0c' 
     and `sales`.`outlet_id` = 'd5b74bdf-5cef-4455-bf99-13cbcb6cbc0c' 
     and `sales`.`order_status` = 'COMPLETED' 
     and `sale_date_time` >= '2016-01-28 00:00:00' 
     and `sale_date_time` <= '2016-11-28 23:59:00' 
    GROUP BY HOUR(CONVERT_TZ(sales.sale_date_time,'UTC','Europe/London')) 
    ORDER BY `sale_date_time` ASC 

UPDATE:

@リック・ジェームス

  • での質問に答えるためには、私は、日時フィールドでsale_date_timeことによってそれをソートする必要があります。時間単位で報告するには、グループ別に必要です。それはまた質問された期間に依存する日、月 - 年等を持っています。
  • デザインのためにUUIDを使用しなければなりませんでした。これらの4つのテーブルの大半はDB全体が約8GBです。インデックスの長さは、私がたくさんの外部キー制約を受けているため、実際のデータサイズよりも大きいです。

Amazonのオーロラには15GBのRAMが搭載されています。

売上表: 0.5ギガバイトのデータ1.3ギガバイトのインデックス

販売アイテム: 1.3ギガバイトのデータ3.2ギガバイトのインデックス

販売支払い: 0.5ギガバイトのデータ1.1ギガバイトのインデックス

すべてのテーブルに照合されますutf8_unicode_ci。

  • これは、MySQL 5.6のAurora 5.6を使用しています。ここでは説明を選択します。

IDのSELECT_TYPEテーブルは、REF行が インデックス条件を用いsales_client_id_outlet_id_foreign、sales_client_id_index、sales_outlet_id_index、sales_sale_date_time_index、sales_order_status_index sales_client_id_index 108 CONST 5352 REF余分

1 PRIMARY販売を濾過key_lenにpossible_keysキーを入力します。どこで使用するか。一時的な使用。 filesortレコードを使用して

1 PRIMARY REF 108は10

1 PRIMARY REF 108は10 MyDB.sales.id MyDB.sales.id

3由来sales_payments sales_payments_client_id_outlet_id_foreign、sales_payments_client_id_index sales_payments_client_id_outlet_id_foreign 108 CONST 5092インデックス条件を使用してrefを。どこで使用するか。一時的な使用。 filesortレコードを使用して

2由来sales_itemsは インデックス条件を用いsales_items_client_id_outlet_id_foreign、sales_items_client_id_index sales_items_client_id_outlet_id_foreign 108 CONST 13340をrefは、どこで使用するか。一時的な使用。 filesortレコードを使用して

2派生した製品でeq_ref PRIMARY、products_id_unique PRIMARY 108 MyDB.sales_items.product_id 1

  • はDBでストアに結果を見て、そこからもらえますように。問題が発生した場合は古い注文を修正し、合計を再構築する必要があるという問題のみです。

希望の結果を得るためにクエリを書き換える他の方法はありますか?

答えて

0
  • ORDER BYGROUP BYと不必要に異なる場合は、追加のソートパスが必要です。
  • UUIDは、データがRAMにキャッシュできるよりも大きい場合、非常に効率が悪いです。テーブルはどれくらい大きいですか? `innodb_buffer_pool_sizeの値は?あなたはどれくらいのRAMを持っていますか?
  • LEFT JOIN (SELECT ...)は、少なくとも5.6まで非常に効率が悪いです。 EXPLAIN SELECT ...を入力して最適化されているか確認してください。どのバージョンを使用していますか?
  • さらに悪いのはLEFT JOIN (SELECT ...) LEFT JOIN (SELECT ...)です。 投稿日:「自動キー」が表示されないので、これは悪いです。それは本当にMySQL 5.6であるかどうか疑問に思います。
  • "サマリーテーブル"を構築​​し維持することが究極の答えとなります。 client_id、outlet_id、order_status、およびsale_HOURを含むPRIMARY KEYが含まれている可能性があります。
  • いずれかのサブクエリは単独で実行されますか?その場合は、サブクエリだけに焦点を当てる別の質問を開始してください。 SHOW CREATE TABLEの出力を入力してください。索引、データ型、サイズ、照合などの表の説明に欠けている多くの詳細があります。追加:まだ必要です。まだいくつか確認する必要があります。可能な解決策:と2つのそれぞれのものLEFT JOIN SELECTs;それらを使用してください。
+0

更新された質問をご覧ください。 – James

+0

追加されました...... –

+0

申し訳ありませんが、それはの誘導テーブルにあります。ちょうど貼り付けられたコードからそれを取り除いた。私は一時テーブルアプローチでそれが改善するかどうかを調べるつもりです。 – James

関連する問題