3

私がサポートしているレガシー製品では、mysql への PHP クエリが動作する場合とハングする場合があります (おそらく有限ですが、そうであれば不当に長い時間です)。私の SQL スキルはかなり限られていますが、mysql で手動でクエリを実行できました。これまでにわかったことは次のとおりです。

テーブル「orders」、「lineItems」、および「lineItemDefns」が与えられた場合、

各オーダーは 1 対多の lineItem であり、lineItem は lineItemDefinitions と 1 対 1 です

各レポート (reportId) を注文のグループとその lineItem データ、および次の SQl クエリにマップするテーブル OrderReports:

SELECT SEC_TO_TIME(SUM(orders.itemCount*lineItems.itemCount*lineItemDefns.estimatedDuration)) as estimatedTotalDuration
FROM orders, lineItems, lineItemDefns
WHERE orders.id=lineItems.parentOrder
  AND lineItemDefns.id=lineItems.definitionId
  AND orders.id in 
      (SELECT DISTINCT orderId 
       FROM OrderReports
       WHERE OrderReports.reportId=98619);

(これは、PHP で DBI getAll を呼び出す直前にクエリ文字列からダンプされたものです。)

2番目の選択を単独で実行すると、ほぼ瞬時に単一の行が返されます。その orderId を 2 番目の選択に置き換えて最初の選択を実行すると、1 秒以内に NULL の EstimatedTotalDuration が返されます。この reportId には 2 つの行しかありません。これは、この注文の 2 つの lineItem 行に対応しています。lineItems (lineItemDefns 内) の EstimatedDurations は両方とも NULL です。

クエリ内のプライマリ ID と外部 ID のすべての ID がインデックス化されます。

すべての数値は整数で、継続時間は秒単位です (int(11))。この場合の itemCounts は 1 です。

しかし、上記のように実行すると、テストデータベースで動作します (30 秒で遅くなります) が、本番データに関する同等のレポートのために不当な時間 (50 分以上) 放置すると完了しません。

レポートがハングしている間に最初の 2 つの部分的なクエリ テストを実行できるため、テーブルがロックされているようには見えません。

誰かが明らかな原因を指摘できますか (たとえば、null EstimatedDurations を処理しますか?)。同様に、次に何を見るべきかについてのヒントはありますか? これは本番データベースなので、他のユーザーに遅延を引き起こす可能性のあることはしたくありません。

クエリを書き直すための提案もいただければ幸いです。

Fedora 7 の mysql 5.0.37 (テスト データベースは Fedora 8 の mysql 5.0.45 です)

ビッグバン セオリーのペニーのように、私が知っているのはそれだけです。ああ、フィグ ニュートンはマサチューセッツ州ニュートンにちなんで名付けられました。;)

4

1 に答える 1

1

問題は、古いバージョンの MySQL がinサブクエリでうまく最適化されなかったことです。特に、 output の可能なすべての行に対してサブクエリを実行しています。. . を何select distinct度も繰り返します。

このサブクエリをfrom句に移動して、問題を修正できます。

SELECT SEC_TO_TIME(SUM(orders.itemCount*lineItems.itemCount*lineItemDefns.estimatedDuration)) as estimatedTotalDuration
FROM orders join
     lineItems
     on orders.id=lineItems.parentOrder join
     lineItemDefns
     on lineItemDefns.id=lineItems.definitionId join
     (SELECT DISTINCT orderId 
      FROM OrderReports
      WHERE OrderReports.reportId=98619
     ) orep
     on orders.id = orep.id

また、すべての結合をfrom句に移動して、標準の ANSI 結合構文を使用しました。

于 2013-06-29T23:35:19.397 に答える