スキーマについて詳しく知らなければ、使用可能な SQL などの特定の提案を提供することは困難です。それでも、やってみます。ここでは、いくつかの一般的な提案を示します。
- 「非常にゆっくりと」定量化するようにしてください。これにより、改良を加えたときに物事が改善されているかどうかを知ることができます。また、処理しているデータの量を定量化します。
- 一時テーブルが必要であることが確実な場合にのみ使用してください。DBMS で発生する可能性のある最も高価な (=== 遅い) 処理の 1 つは、テーブルへのデータの書き込みです。一時テーブルが必要ない場合は、使用しないでください。
- 可能であれば、生データから HTML で表示したいテーブルの正しい列と行を生成する単一の SQL クエリを作成します。次に、コマンドライン mySQL クライアントでそのクエリを実行し、EXPLAIN コマンドを使用して、mySQL に何をしようとしているのかを知らせます。ここを参照してください: http://dev.mysql.com/doc/refman/5.0/en/explain.html
そのクエリがどのように機能するかについて、より具体的な提案を次に示します。入力テーブルにこのスキーマがあるとします。
vendorname
standard_vendor_name (corrects misspells in vendor name, etc.)
vendor_category (character string)
quarter (integer)
spend (floating point)
結果として、これらの列を持つテーブルが必要だとしましょう
vendor_category
vendor (standardized spelling)
spend_q1
spend_q2
spend_q3
spend_q4
申し訳ありませんが、出力でベンダー名とカテゴリをどのように扱っているかについての質問がわかりません。カテゴリを表示してから、各ベンダーの名前を表示し、カテゴリ別に並べ替えているだけだと思います。
quarter
また、入力テーブルにどのように保存しているのかわかりません。1Q2011 - 2Q2012 に対して 20111、20112、20113、20114、20121、20122 のような数値形式を使用しているとします。
ニヤニヤ笑いのために、html テーブルに 4 つの連続した四半期を表示したいとします。
では、どうぞ。
表示したい最新の四半期の ID に基づいて、必要な 4 つの四半期 ID を生成するための小さなサブクエリが必要です。これは提供する必要があります。
SELECT DISTINCT QUARTER
FROM INFO
WHERE QUARTER <= ~~~the most recent quarter~~~
ORDER BY QUARTER DESC
LIMIT 0,4
常に最新の四半期から開始する場合はWHERE QUARTER <= ~~~the most recent quarter~~~
、この小さなサブクエリを除外するだけで、最新のデータが取得されます。
次に、四半期のリストのサブクエリをサブクエリに構築して、最新の四半期のデータを生成する必要があります。
SELECT I.QUARTER, I.VENDOR_CATEGORY, I.STANDARD_VENDOR_NAME, SUM(I.SPEND) SPEND
FROM INFO I
JOIN (
SELECT DISTINCT QUARTER
FROM INFO
WHERE QUARTER <= ~~~the most recent quarter~~~
ORDER BY QUARTER DESC
LIMIT 0,1
) Q ON I.QUARTER=Q.QUARTER
GROUP BY I.QUARTER, I.VENDOR_CATEGORY, I.STANDARD_VENDOR_NAME
これは、基本的な四半期ごとのルックアップのビルディング ブロックです。この時点で、INFO テーブルに QUARTER および VENDOR_CATEGORY 列にインデックスが必要になることは明らかです。
これらの両方、または (QUARTER, VENDOR_CATEGORY, STANDARD_VENDOR_NAME) をまとめて複合インデックスが必要な場合があります。しかし、物事を機能させます。次に、EXPLAIN の出力を見てください。次に、他のインデックスを追加してみてください。先に進む前に、このビルディング ブロック クエリを最適化するためにインデックスをいじる価値があります。
前の四半期ごとに 1 つずつ、これらの小さなサブクエリがさらに 3 つ必要になります。LIMIT 0,1
サブクエリは、 、LIMIT 1,1
、LIMIT 3,1
、およびを除いてビルディング ブロックと同じLIMIT 4,1
です。
また、表示する必要があるすべての VENDOR_CATEGORY と STANDARD_VENDOR_NAME の組み合わせのマスター リストも必要です。このクエリは、検討している四半期のいずれかに 1 回以上表示されたカテゴリ/ベンダーの組み合わせの結果をポップアウトします。
SELECT DISTINCT I.VENDOR_CATEGORY, I.STANDARD_VENDOR_NAME
FROM INFO I
JOIN (
SELECT DISTINCT QUARTER
FROM INFO
WHERE QUARTER <= ~~~the most recent quarter~~~
ORDER BY QUARTER DESC
LIMIT 0,4
) Q ON I.QUARTER=Q.QUARTER
これで LEFT JOIN を実行しないでください。そうしないと、直近の 4 四半期でお金を使っていないものを含む、すべてのカテゴリ/ベンダー アイテムになってしまいます。
次に、すべてをまとめる必要があります。とてつもなく冗長になります (SQL は面白くありませんか?)。これらの構成要素をすべて結合する必要があります。以下は、ビルディング ブロックの場所を示すコメントを含む、グランド クエリの概要です。
SELECT A.VENDOR_CATEGORY, A.STANDARD_VENDOR_NAME, Q.SPEND, R.SPEND, S.SPEND, T.SPEND
FROM (
/* category combinations */
)A
LEFT JOIN (
/* most recent quarter spend */
)Q ON ( A.VENDOR_CATEGORY=Q.VENDOR_CATEGORY
AND A.STANDARD_VENDOR_NAME=Q.STANDARD_VENDOR_NAME)
LEFT JOIN (
/* second most recent quarter spend */
)R ON ( A.VENDOR_CATEGORY=R.VENDOR_CATEGORY
AND A.STANDARD_VENDOR_NAME=R.STANDARD_VENDOR_NAME)
LEFT JOIN (
/* third most recent quarter spend */
)S ON ( A.VENDOR_CATEGORY=S.VENDOR_CATEGORY
AND A.STANDARD_VENDOR_NAME=S.STANDARD_VENDOR_NAME)
LEFT JOIN (
/* fourth most recent quarter spend */
)T ON ( A.VENDOR_CATEGORY=T.VENDOR_CATEGORY
AND A.STANDARD_VENDOR_NAME=T.STANDARD_VENDOR_NAME)
ORDER BY A.VENDOR_CATEGORY, A.STANDARD_VENDOR_NAME
サブクエリをこのアウトラインに挿入するのはあなたに任せます。
おそらく、このようなものを使用して一時テーブルを生成したことがあるでしょう。しかし、うまくいけば、この大きなクエリを使用してレポートを生成できます。情報テーブルに無数の行が含まれていない限り、テーブルに正しくインデックスを付ければ、かなり高速に実行されます。
膨大な数の行がある場合は、高速ディスクと数ギガバイトの RAM を備えたより大きな mySQL サーバーを求める大企業で働いている可能性があります。これにより、特にインデックス作成が完了すると、速度も向上します。