1

次のことを行うクエリを改善しようとしています。

すべてのジョブについて、すべてのコストを合計し、請求額を合計して、利益/損失を計算します。コストは、購入注文、users_events (エンジニアが割り当てた時間/現場で費やした時間)、使用された在庫など、いくつかの異なるテーブルから取得されます。
クエリは、作業用のサイトの名前などの他の列も出力する必要があります。列を並べ替えることができます (このすべての後に ORDER BY が追加されます)。

SELECT
    jobs.job_id,
    jobs.start_date,
    jobs.end_date,
    events.time,
    sites.name site,
    IFNULL(stock_cost,0) stock_cost,
    labour,
    materials,
    labour+materials+plant+expenses revenue,
    (labour+materials+plant)-(time*3557/360000+IFNULL(orders_cost,0)+IFNULL(stock_cost,0)) profit,
    ((labour+materials+plant)-(time*3557/360000+IFNULL(orders_cost,0)+IFNULL(stock_cost,0)))/(time*3557/360000+IFNULL(orders_cost,0)+IFNULL(stock_cost,0)) ratio

FROM
    jobs

    LEFT JOIN (
        SELECT
            job_id,
            SUM(labour_charge) labour,
            SUM(materials_charge) materials,
            SUM(plant_hire_charge) plant,
            SUM(expenses) expenses
        FROM invoices
        GROUP BY job_id
        ORDER BY NULL
    ) invoices USING(job_id)

    LEFT JOIN (
        SELECT
            job_id,
            SUM(IF(start_onsite && end_onsite,end_onsite-start_onsite,end-start)) time,
            SUM(travel+parking+materials) user_expenses
        FROM users_events
        WHERE type='job'
        GROUP BY job_id
        ORDER BY NULL
    ) events USING(job_id)

    LEFT JOIN (
        SELECT
            job_id,
            SUM(IFNULL(total,0))*0.01 orders_cost
        FROM purchaseorders
        GROUP BY job_id
        ORDER BY NULL
    ) purchaseorders USING(job_id)

    LEFT JOIN (
        SELECT
            location job_id,
            SUM(amount*cost))*0.01 stock_cost
        FROM stock_location
        LEFT JOIN stock_items ON stock_items.id=stock_location.stock_id
        WHERE location>=3000 AND amount>0 AND cost>0
        GROUP BY location
        ORDER BY NULL
    ) stock USING(job_id)

    LEFT JOIN contacts_sites sites ON sites.id=jobs.site_id;

私はこれを読みました:http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.htmlしかし、そこに何かを適用できるかどうか/方法がわかりません。テスト目的で、左、右、中央のフィールドにあらゆる種類のインデックスを追加しようとしましたが、EXPLAIN 出力は改善されませんでした。

+----+-------------+----------------+--------+------------------------+---------+---------+------------------------------------+-------+-------------------------------+
| id | select_type | table          | type   | possible_keys          | key     | key_len | ref                                | rows  | Extra                         |
+----+-------------+----------------+--------+------------------------+---------+---------+------------------------------------+-------+-------------------------------+
|  1 | PRIMARY     | jobs           | ALL    | NULL                   | NULL    | NULL    | NULL                               |  7088 |                               |
|  1 | PRIMARY     | <derived2>     | ALL    | NULL                   | NULL    | NULL    | NULL                               |  5038 |                               |
|  1 | PRIMARY     | <derived3>     | ALL    | NULL                   | NULL    | NULL    | NULL                               |  6476 |                               |
|  1 | PRIMARY     | <derived4>     | ALL    | NULL                   | NULL    | NULL    | NULL                               |   904 |                               |
|  1 | PRIMARY     | <derived5>     | ALL    | NULL                   | NULL    | NULL    | NULL                               |   531 |                               |
|  1 | PRIMARY     | sites          | eq_ref | PRIMARY                | PRIMARY | 4       | bestbee_db.jobs.site_id            |     1 |                               |
|  5 | DERIVED     | stock_location | ALL    | stock,location,amount,…| NULL    | NULL    | NULL                               |  5426 | Using where; Using temporary; |
|  5 | DERIVED     | stock_items    | eq_ref | PRIMARY                | PRIMARY | 4       | bestbee_db.stock_location.stock_id |     1 | Using where                   |
|  4 | DERIVED     | purchaseorders | ALL    | NULL                   | NULL    | NULL    | NULL                               |  1445 | Using temporary;              |
|  3 | DERIVED     | users_events   | ALL    | type,type_job          | NULL    | NULL    | NULL                               | 11295 | Using where; Using temporary; |
|  2 | DERIVED     | invoices       | ALL    | NULL                   | NULL    | NULL    | NULL                               |  5320 | Using temporary;              |
+----+-------------+----------------+--------+------------------------+---------+---------+------------------------------------+-------+-------------------------------+

生成される行は 5 x 10^21 (このクエリの最適化を開始する前の 3 x 10^42 から減少しました!)
現在、実行に 7 秒かかります (26 から減少) が、1 秒未満にしたいと考えています。

ところで、GROUP BY x ORDER BY NULL は、サブクエリから不要なファイルソートを排除する優れた方法です。( http://www.mysqlperformanceblog.com/2006/09/04/group_concat-useful-group-by-extension/から)

4

1 に答える 1

0

私の質問に対するあなたのコメントに基づいて、私は次のことを行います...

一番上に...

SELECT STRAIGHT_JOIN (「STRAIGH_JOIN」キーワードを追加するだけ)

次に、請求書、イベント、p/o などのサブクエリごとに、ORDER BY を JOB_ID に明示的に変更して、プライマリ JOBS テーブル結合に対する最適化に役立つようにします。

最後に、各サブクエリ テーブルに Job_ID (Invoices、User_events、PurchaseOrders、Stock_Location) のインデックスがあることを確認します。

さらに、Stock_Location テーブルの場合、
(job_id, location, amount) に複合インデックスを設定することで、サブクエリの WHERE 句を支援することができます。キーと 3 つの where 条件要素がある場合でも、3 つのフィールドの深さで十分です。

于 2011-06-22T11:54:15.380 に答える