sql >> データベース >  >> RDS >> Mysql

高価なクエリはデータベースサーバーをダウンさせます-軽減する方法を探しています

    うーん、私はこれらの線に沿ってあなたのクエリを書いてみるかもしれません:

    SELECT Sale_Item.deleted, Sale_Item.deleted_by,
           Sale_Item.sale_time, Sale_Item.sale_date,
           Sale_Item.comment,
           Sale_Item.payment_type,
           Sale_Item.customer_id,
           Sale_Item.employee_id,
           Sale_Item.category,
           Sale_Item.sale_id, Sale_Item.item_id, NULL as item_kit_id, Sale_Item.line, 
           Sale_Item.supplier_id,
           Sale_Item.serialnumber, Sale_Item.description,
           Sale_Item.quantity_purchased, Sale_Item.item_cost_price, Sale_Item.item_unit_price,
           Sale_Item.discount_percent,
           Sale_Item.lineSubtotal,
           Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + Sale_Item.non_cumulative) * COALESCE(Tax.cumulative, 0) AS lineTax,
           Sale_Item.lineSubtotal + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + (Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative, 0) + Sale_Item.non_cumulative) * COALESCE(Tax.cumulative, 0)) AS lineTotal,
           Sale_Item.lineSubtotal - (Sale_Item.item_cost_price * Sale_Item.quantity_purchased) AS profit
    
    FROM (SELECT Sale.deleted, Sale.deleted_by,
                 Sale.sale_time, DATE(Sale.sale_time) AS sale_date,
                 Sale.comment,
                 Sale.payment_type,
                 Sale.customer_id,
                 Sale.employee_id,
                 Item.category,
                 Sale_Item.sale_id, Sale_Item.item_id, NULL as item_kit_id, Sale_Item.line, 
                 Sale_Item.supplier_id,
                 Sale_Item.serialnumber, Sale_Item.description,
                 Sale_Item.quantity_purchased, Sale_Item.item_cost_price, Sale_Item.item_unit_price,
                 Sale_Item.discount_percent,
                 (Sale_Item.item_unit_price * Sale_Item.quantity_purchased) - (Sale_Item.item_unit_price * Sale_Item.quantity_purchased * Sale_Item.discount_percent / 100) as lineSubtotal                 
          FROM phppos_sales_items Sale_Item
          JOIN phppos_sales Sale
            ON Sale.sale_id = Sale_Item.sale_id
               AND Sale.sale_time >= TIMESTAMP('2014-04-01')
               AND Sale.sale_time < TIMESTAMPADD(MONTH, 1, '2014-04-01')
               AND Sale.location_id = 1
               AND Sale.store_account_payment = 0) Sale_Item
    
    LEFT JOIN (SELECT Tax.sale_id, Tax.item_id, Tax.line,
                      SUM(CASE WHEN Tax.cumulative = 1 THEN Tax.percent ELSE 0 END) as cumulative,
                      SUM(CASE WHEN Tax.cumulative <> 1 THEN Tax.percent ELSE 0 END) as non_cumulative
               FROM phppos_sales_item_taxes Tax
               JOIN phppos_sales Sale
                 ON Sale.sale_id = Tax.sale_id
                    AND Sale.sale_time >= TIMESTAMP('2014-04-01')
                    AND Sale.sale_time < TIMESTAMPADD(MONTH, 1, '2014-04-01')
                    AND Sale.location_id = 1
                    AND Sale.store_account_payment = 0
               GROUP BY Tax.sale_id, Tax.item_id, Tax.line) Tax
           ON Tax.sale_id = Sale_Item.sale_id
              AND Tax.item_id = Sale_Item.sale_id
              AND Tax.line =Sale_Item.line 
    

    整理のためにいくつかの列を移動しました。これは処理時間に大きな影響を与えないはずです。

    phppos_suppliersへの参照を削除しました として:

    1. テーブルの列は使用しません
    2. これはLEFT JOIN 、つまり、そこに行が存在する必要はありません。

    GROUP BYを移動しました phppos_sales_item_taxesのため、新しいサブクエリに追加します 指定された基準に対して重複する行を持つ可能性がある唯一のテーブルです。 phppos_salesへの参照を含めました MySQLのオプティマイザ(または実際にはどれか)がシテリアを押し下げるのに十分賢いかどうかわからないからです。

    クエリの主要部分がサブクエリに移動されたため、lineSubtotalの数式を入力する必要はありません。 複数回。全体を通して同じ式を使用しましたが、利用可能な簡略化されたバージョンがあります:

    Sale_Item.item_unit_price * Sale_Item.quantity_purchased * (1 - (Sale_Item.discount_percent / 100)) as lineSubtotal  
    
    Sale_Item.lineSubtotal * COALESCE(Tax.non_cumulative + Tax.cumulative + Tax.non_cumulative * Tax.cumulative, 0) as Tax
    

    ....ただし、これらは操作の順序について(当然のことながら)扱いにくい傾向があるため、アカウンティングによって実行する必要がある場合があります。このかもしれません 実行時間が速くなりますが、私はそれを疑っています。ほとんどの場合、これは用語をより読みやすいものに単純化することです。

    クエリの残りの半分にテーブルレイアウトを指定していませんが、類似していると思います。関連する変更は、読者の演習として残されています。

    一般的な緩和戦略

    クエリを変更することでスピードアップする可能性があるだけでなく、問題を減らすためにできることがいくつかあります。

    1. アプリケーション層で、このクエリ(および場合によっては他のクエリ)に、後で結果を取得できるジョブ送信プロセスを強制的に実行させます。このクエリの新しいコピーは、前のクエリが完了するまで実行できません。 phpにはこのための既存のライブラリがあると思います。一般的に、提出を制限するだけで十分な場合があります。
    2. 取得するデータはキャッシュに適しているようです-最後に処理されたsale_dateの前にすべてを保存します 、そしてその場で新しい情報を取得するだけです(ただし、変換は実際にはそれほど違いはありません オリジナルから-ただし、単にそれ以上の結合を行わないことが役立つ場合があります。
    3. 現在の処理期間中のクエリを禁止します。これにより、システムがまだコミットされていない行にアクセスしようとするのを防ぎ、変更中のインデックスページから離れる可能性があります。この種のトリックは、同時I/Oを利用するようにストレージがレイアウトされている場合に最適に機能します。



    1. PythonMySQdbでレコードが存在するかどうかを確認する方法

    2. MySQLでタスクマネージャのデータベースを設計するためのガイド

    3. json配列をmysqlデータベースに挿入する方法

    4. OmniDBを使用してPostgreSQL12のパフォーマンスを監視する方法–パート2