3

会社で取り組んでいるプロジェクトの最も効率的なテーブル構造/SQL コードに関するアドバイスを探しています。私はプロの開発者ではないので、よりシンプルなソリューションが望ましいです。

プロジェクト要件:

会計四半期ごとのベンダー カテゴリ別の総支出を表示する HTML テーブルを作成したいと考えています。各カテゴリはクリックして展開し、ベンダー レベル x ビジネス ユニット レベルの支出を取得できるリンクになっています。

私はすでにこれを稼働させています。PHP と MySQL を組み込みました。ただし、テーブルを拡張するために実行するクエリは、場合によっては非常に遅く実行されます。テーブル構造とクエリを見直して、プロセス全体をより効率的かつ柔軟にしたいと考えています。

私が持っているデータの要約

私は四半期ごとに、すべてのビジネス ユニットから、ベンダーごとの支出に関する生データを取得しています。また、ベンダー名をベンダー カテゴリ (スターバックス -> レストランなど) に一致させるデコーダ リングもあります。

現在のプロセス 四半期ごとのデータを、次の列を使用して、spendfile というテーブルにロールアップします。

  • 業者名
  • standard_vendor_name (ベンダー名のスペルミスなどを修正)
  • vendor_category
  • クォーター
  • 費やす

ユーザーから (初めて) カテゴリを下にして HTML テーブルを表示し、別の列で四半期ごとに支出するように要求した場合、次の列を持つ treetable という一時テーブルを作成します。

  • rowlabel (表の下側に表示されるカテゴリ/ベンダーの名前)
  • 支出Q1 (各四半期のベンダーとの支出の別の列)
  • 第 2 四半期の費用
  • 第 3 四半期の費用
  • 第 4 四半期の費用
  • 費やす...

このテーブルを取得するには、一意のベンダー カテゴリをすべて選択し、四半期ごとに支出を合計し、最後に各四半期の四半期ごとの合計支出をカテゴリ リストに結合する必要があることに注意してください (したがって、5 ~ 6 個の結合を行っています。期間ごとに)。

次に、html テーブルとしてレンダリングします (かなり簡単です)。

ユーザーがカテゴリをクリックして詳細を取得すると、同様のプロセスが実行されます。ベンダーの一意のリストを取得し、支出を合計し (今回は特定のカテゴリのすべてのベンダーについて)、すべての期間を個別の列として結合します。

最後のステップは、新しくドリルダウンされたデータをツリーテーブル テーブルの適切な場所 (すべてのベンダーが属するカテゴリの下) に統合することです。

これを行うためのより良い方法について誰かアイデアがありますか? 私がやろうとしていることは理にかなっていますか?

ありがとう

4

1 に答える 1

0

スキーマについて詳しく知らなければ、使用可能な SQL などの特定の提案を提供することは困難です。それでも、やってみます。ここでは、いくつかの一般的な提案を示します。

  1. 「非常にゆっくりと」定量化するようにしてください。これにより、改良を加えたときに物事が改善されているかどうかを知ることができます。また、処理しているデータの量を定量化します。
  2. 一時テーブルが必要であることが確実な場合にのみ使用してください。DBMS で発生する可能性のある最も高価な (=== 遅い) 処理の 1 つは、テーブルへのデータの書き込みです。一時テーブルが必要ない場合は、使用しないでください。
  3. 可能であれば、生データから 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,1LIMIT 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 サーバーを求める大企業で働いている可能性があります。これにより、特にインデックス作成が完了すると、速度も向上します。

于 2012-06-07T20:33:02.893 に答える