优化麻烦的查询

时间:2011-01-18 14:33:15

标签: sql mysql optimization

我正在通过2个mysql表格中的php生成PDF,其中包含一个表格。在较大的表上,脚本占用了大量内存,并开始成为一个问题。

我的第一张表包含“检查”。每天有很多行。这与用户表有多对一的关系。

表“检查”


          ID       区域       inpsection_date       inpsection_agent_1       inpsection_agent_2       inpsection_agent_3    

id(int)
area(varchar) - 是8个“区域”之一,即:混凝土,土壤,土方工程 inspection_date(int) - unix时间戳
inspection_agent_1(int) - 用户ID
inspection_agent_2(int) - 用户ID
inspection_agent_3(int) - 用户ID


第二个表是用户的信息。我只需要将名称加入“inspection_agents_x”

          ID       名称    

最终表格将在PDF中,需要通过以下方式组织数据:

  • 白天
  • 由用户查找当天用户“检查”的每个“区域”

混凝土 土壤 土方
2011年1月18日
Jon Doe X
简·多伊 X X

等等每一天。现在我只是对名称进行简单连接,然后在代码端组织所有内容。我知道,就查询而言,我会在桌子上留下很多东西,我只是想不出办法去做。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

我会这样:

select i.*, u1.name, u2.name, u3.name from inspections i left join users u1 on (i.inspection_agent_id1 = u1.id) left join users u2 on (i.inspection_agent_id2 = u2.id) left join users u3 on (i.inspection_agent_id3 = u3.id) order by i.inspection_date asc;

然后选择不同的区域名称并记住它们,或者如果您有任何区域,则从区域表中获取它们:

从检查中选择不同的区域;

然后它就是foreach:

$day = "";
foreach($inspection in $inspections)
{
   if($day == "" || $inspection["inspection_date"] != $day)
   {
       //start new row with date here
   }

   //start standard row with user name
}

目前尚不清楚您是否必须每次都显示所有用户(即使其中一些用户没有进行检查),如果必须,您应该获取用户一次并循环$ users并搜索用户$ inspection row。

答案 1 :(得分:1)

Select U.name
    , user_inspections.inspection_date
    , Min( Case When user_inspections.area = 'Concrete' Then 'X' End ) As Concrete
    , Min( Case When user_inspections.area = 'Soils' Then 'X' End ) As Soils
    , Min( Case When user_inspections.area = 'Earthwork' Then 'X' End ) As Earthwork
From users As U
    Join    (
            Select area, inspection_date, inspection_agent1 As user_id
            From inspections
            Union All
            Select area, inspection_date, inspection_agent2 As user_id
            From inspections
            Union All
            Select area, inspection_date, inspection_agent3 As user_id
            From inspections
            ) As user_inspections
        On user_inspections.user_id = U.id
Group By U.name, user_inspections.inspection_date

这实际上是一个静态交叉表。这意味着您需要知道在设计时应该在查询中输出的所有区域。

此查询存在问题的原因之一是您的架构未规范化。您的检查表应如下所示:

Create Table inspections
    (
    id int...
    , area varchar...
    , inspection_date date ...
    , inspection_agent int References Users ( Id )
    )

这样可以避免内部的Union All查询获得所需的输出。