0

関連する販売、販売アイテム、およびスタッフ メンバーに基づいて、販売情報の行を作成するクエリがあります。私の開発サーバーでは売上が 10 ~ 20 で問題なく動作しますが、売上が 5,000 を超えるエンド サーバーで実行すると、システム全体が停止します。

SELECT Sales.SaleID,
Sales.StaffID,
Sales.CustomerID,
Sales.Timestamp,
Sales.Refunded,
Sales.PaymentType,
Staff.Forename AS staffForename,
Staff.Surname AS staffSurname,
itemList, sumOfCost,
sumOfPrice,
a.sumOfPrice - a.sumOfCost AS sumOfProfit

FROM Sales
INNER JOIN Staff ON Sales.StaffID = Staff.StaffID
LEFT JOIN (
              SELECT SaleID,
              GROUP_CONCAT(Quantity, ' x ', Name) itemList,
              SUM(Cost*Quantity) sumOfCost, SUM(Price*Quantity) sumOfPrice
              FROM SaleItems GROUP BY SaleID
          ) a
ON a.SaleID = Sales.SaleID

WHERE Sales.Deleted = '0'
AND Sales.ShopID = '0'
ORDER BY Sales.Timestamp DESC LIMIT 0,15

どんな助けでも大歓迎です!このクエリの最後の試行には 65 秒かかりました...

4

2 に答える 2

0

まず、サブクエリがありません (私の意見では)。私にとって、サブクエリとは、クエリ内の別のテーブルのレコードに依存し、行ごとに処理されるものです。あなたのバージョンは、一度実行される完全なクエリであり、完全な結果セットを取得し、それを他のテーブルへの結合の基礎として使用します。

次に、すべての JOIN 条件 (スタッフ ID、セールス ID などへの結合) を処理するなど、他のユーザーのコメントに記載されているように、すべてのテーブルに明らかなインデックスが必要です。ただし、CRITERIA を最適化するのに役立つインデックスも必要です。この場合、次のインデックスがあります。

(Deleted, ShopID, SaleID )

「SaleID」列を含める理由は、GROUP BY および ORDER BY 句の最適化に使用するためです。最近の 15 件の売上のみが必要なようです。タイムスタンプは販売トランザクションに直接関連付けられるため、SaleID # 1 のタイムスタンプは SaleID #2 の前にあることを意味し、Sale ID #3、#4、#5 についても同様です。そうは言っても、同じ結果を達成するセール ID DESCENDING で注文するだけです。

さて、あなたの質問のために。あなたが最初に持っていたのは、すべての販売、すべてのアイテムをそれぞれのコストと価格で集計する事前クエリでした。それがおそらくあなたのパフォーマンスを殺しているのです。それだけで、最も外側の WHERE 基準を満たさないすべてのレコードを破棄します。

これで、私がどこから来たのかがわかったので、次のことを行います。私の「プレクエリ」は、削除されたショップIDの基準の最新の15件の売上を取得するための売上テーブルからの選択に他なりませんが、売上IDの降順で並べ替えられます(基本的に、上記の例のタイムスタンプと同じもの)...そしてそれを 15 に制限します。次に、結合とグループ化を終了して、売上のデータベース全体ではなく、15 の売上に関連する項目のみを集計するようにします。「PreQuery」は最新のものから事前に並べ替えられているため、外側の結果セットを並べ替える必要はありません。

1 つの販売 ID に対して 10 の項目があり、販売の最終的な総合計エントリのみを表示する可能性があるため、グループ化を外側のレベルに保持する必要があります。

    SELECT 
          S.SaleID,
          S.StaffID,
          S.CustomerID,
          S.Timestamp,
          S.Refunded,
          S.PaymentType,
          Staff.Forename AS staffForename,
          Staff.Surname AS staffSurname,
          GROUP_CONCAT(SI.Quantity, ' x ', SI.Name) itemList,
          SUM(SI.Cost*SI.Quantity) sumOfCost, 
          SUM(SI.Price*SI.Quantity) sumOfPrice,
          SUM(SI.Price*SI.Quantity) - SUM(SI.Cost*SI.Quantity) AS sumOfProfit
       FROM 
          ( select Sales.SaleID
               FROM Sales
               WHERE Sales.Deleted = '0'
                  AND Sales.ShopID = '0'
               ORDER BY 
                  Sales.SaleID DESC 
               LIMIT 
                  0,15 ) PreQuery
             JOIN Sales S
                on PreQuery.SaleID = S.SaleID
                JOIN SaleItems SI
                   ON Sales.SaleID = SI.SaleID
                JOIN Staff 
                   ON S.StaffID = Staff.StaffID
   group by
      S.SaleID
于 2013-01-28T11:46:51.833 に答える
0

私は気が狂っているだけですか、それともこれはまさに私が必要としているものですか?

SELECT Sales.SaleID,
Sales.StaffID, 
Sales.CustomerID, 
Sales.Timestamp, 
Sales.Refunded, 
Sales.PaymentType, 
Staff.Forename AS staffForename, 
Staff.Surname AS staffSurname, 
GROUP_CONCAT(SaleItems.Name) AS ItemList, 
SUM(Cost) AS sumOfCost, 
SUM(Price) AS sumOfCost, 
SUM(Price) - SUM(Cost) AS sumOfProfit 
FROM Sales 
JOIN Staff ON Sales.StaffID = Staff.StaffID 
JOIN SaleItems ON Sales.SaleID = SaleItems.SaleID 
WHERE Sales.Deleted = '0' 
AND Sales.ShopID = '0' 
GROUP BY SaleItems.SaleID 
ORDER BY Sales.Timestamp DESC 
LIMIT 0,15

正しい結果が得られているように見えますが、非常に複雑ではないように思われるため、以前に見たことがないことを少し混乱させますか?

于 2013-01-28T11:22:13.990 に答える