3

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

项目要求:

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

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

我拥有的数据摘要

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

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

  • 供应商名称
  • standard_vendor_name(更正供应商名称中的拼写错误等)
  • 供应商类别
  • 四分之一
  • 花费

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

  • rowlabel(出现在表格下方的类别/供应商名称)
  • 支出 Q1(每个季度与供应商的支出的单独列)
  • 花费Q2
  • 花费Q3
  • 花费Q4
  • 花费...

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

然后我呈现为 html 表(相当简单)

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

最后一步是将新的钻取数据合并到正确位置的树形表中(在所有供应商所属的类别下方)。

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

谢谢

4

1 回答 1

0

如果不了解有关您的架构的更多信息,很难提供具体的建议(例如可能使用的 SQL)。不过,我会努力的。以下是一些一般性建议。

  1. 尝试量化“非常缓慢”,这样您就可以知道您是否在改进时进行改进。还要量化您要处理的数据量。
  2. 仅在您绝对确定需要临时表时才使用它们。DBMS 中可能发生的最昂贵(=== 慢)的事情之一是将数据写入表。如果您不需要临时表,请不要使用它们。
  3. 如果可以,请创建一个 SQL 查询,为您希望从原始数据以 HTML 格式显示的表生成正确的列和行。然后,在命令行 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 表格中显示任意四个连续的季度,只是为了笑。

所以,我们开始吧。

我们需要一个小子查询来根据您要显示的最近一个季度的 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,1除了、LIMIT 1,1LIMIT 3,1和之外,子查询与构建块相同LIMIT 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

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

您可能已经使用过类似的方法来生成临时表。但如果你做对了,你可以简单地使用这个大查询来生成你的报告。除非您的信息表有数以亿计的行,否则如果您正确索引表,它将运行得相当快。

如果您确实有数以亿计的行,那么您可能为一家大公司工作,该公司可以为具有快速磁盘和数 GB RAM 的更大的 mySQL 服务器而生。这也将加快速度,尤其是在您制定索引后。

于 2012-06-07T20:33:02.893 回答