改进的表结构,用于查询季度支出数据

时间:2012-06-07 18:00:28

标签: mysql database-design

我正在为我正在为我的公司工作的项目寻找最有效的表结构/ SQL代码的建议。我不是专业开发人员,所以更简单的解决方案更可取。

项目要求:

我想创建一个HTML表格,按财务季度按供应商类别显示汇总支出,其中每个类别都是可以点击以扩展以获得供应商级别x业务单位级别支出的链接。

我已经开始运行了。我用PHP和MySQL构建。但是,在某些情况下,我运行以扩展表的查询运行非常缓慢。我想彻底检查我的表结构并查询以使整个过程更加高效和灵活。

我拥有的数据摘要

我每个季度都会从供应商支出的每个业务部门获取原始数据。我还有一个解码器环,可以将供应商名称与供应商类别相匹配(例如星巴克 - >餐厅)。

我当前的流程 我将季度数据汇总到名为spendfile的表中,其中包含以下列:

  • VENDORNAME
  • standard_vendor_name(更正供应商名称中的拼写错误等)
  • vendor_category
  • 季度

当我向用户请求(第一次)查看带有类别的HTML表并在不同的列中按季度支出时,我创建了一个名为treetable的临时表,其中包含以下列:

  • rowlabel(显示在表格下方的类别/供应商的名称)
  • spendQ1(每季度与供应商分开的单独栏目)
  • spendQ2
  • spendQ3
  • spendQ4
  • 花...

请注意,为了获得此表,我需要选择所有独特的供应商类别,然后按季度总计每个季度的支出,最后将每个季度的季度总支出加入到类别列表中(所以我正在做5-6加入,每个时间段1)。

然后我渲染为html表(相当简单)

当用户点击某个类别以获取更多详细信息时,我会经历一个类似的过程:获取供应商的唯一列表,汇总花费(此时间针对特定类别的所有供应商)并将所有时间段作为单独的列加​​入。

最后一步是将新钻取的数据合并到右侧的treetable表(所有供应商所属的类别下)。

有没有人对更好的方法有任何想法?我想做的事情有意义吗?

由于

1 个答案:

答案 0 :(得分:0)

很难提供具体的建议 - 比如可能的SQL使用 - 而不了解您的架构。不过,我会试试。以下是一些一般性建议。

  1. 尝试量化“非常缓慢”,这样您就可以知道在进行改进时是否正在改进。还要量化您要处理的数据量。
  2. 如果您完全确定需要它们,则只使用临时表。在DBMS中可能发生的最昂贵的(===慢)事情之一是将数据写入表。如果您不需要临时表,请不要使用它们。
  3. 如果您可以这样做,请创建一个SQL查询,为您希望在原始数据中以HTML显示的表生成正确的列和行。然后,在命令行mySQL客户端中运行该查询,并使用EXPLAIN命令让mySQL告诉您它正在尝试做什么。见这里:http://dev.mysql.com/doc/refman/5.0/en/explain.html
  4. 以下是有关该查询如何工作的一些更具体的建议。假设您的输入表具有此架构。

    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的。假设您在2011年第一季度 - 2012年第二季度使用的数字格式如20111年,20112年,20113年,20114年,20121年,20122年。

    假设您想要在html表格中连续四个季度显示,只是为了咧嘴笑。

    所以,我们走了。

    我们需要一个小子查询来根据您想要显示的最近一个季度的ID生成您需要的四个季度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输出。然后尝试添加其他索引。在进一步研究之前,值得摆弄索引以优化此构建块查询。

    我们还需要三个这样的小子查询,每个子季查询一个。子查询与构建基块相同,但LIMIT 0,1LIMIT 1,1LIMIT 3,1LIMIT 4,1除外。

    我们还需要一个我们需要显示的所有VENDOR_CATEGORY和STANDARD_VENDOR_NAME组合的主列表。此查询会弹出在您考虑的任何季度中出现一次或多次的任何类别/供应商组合的结果。

    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,否则您最终将获得所有类别/供应商项目,包括您最近四个季度未花钱的类别。

    现在我们需要把它们放在一起。事情变得荒谬冗长(不是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
    

    我将留给您将子查询插入此大纲。

    您可能已经使用过类似的东西来生成临时表。但如果你做对了,你可以简单地使用这个大查询生​​成你的报告。除非你的信息表有很多行,否则如果你正确地索引你的表,它会很快运行。

    如果你有大量的行,你可能会为一家大公司工作,这家公司可以为更大的mySQL服务器提供快速磁盘和几千兆字节的RAM。这也会加快速度,尤其是在编制索引之后。