如何加快我的PHP PSQL查询

时间:2012-12-18 16:35:28

标签: php postgresql

要求的表格定义

                Table "public.call_record"
     Column      |          Type          |   Modifiers
-----------------+------------------------+---------------
 cntrct_id       | character varying(15)  | not null
 call_regard     | text                   |
 port_type       | character varying(9)   |
 inst            | text                   |
 info_taken      | character varying(40)  |
 log_date        | date                   | not null
 log_time        | time without time zone | not null
 act_taken       | text                   |
 use_material    | text                   |
 targ_pest       | integer                |
 work_comp_by    | text                   |
 emp_no          | integer                |
 comp_date       | date                   |
 job_start_time  | time without time zone |
 job_leave_time  | time without time zone |
 comp_val        | boolean                | default false
 fti_call_regd   | public.tsvector        |
 fti_inst        | public.tsvector        |
 fti_act_take    | public.tsvector        |
 route           | character(3)           |
 act_port        | text                   |
 targ_pest_opt   | text                   |
 call_regard_opt | text                   |
 targpest_other  | text                   |
 date_sched      | date                   |
 custord_num     | integer                |
 dist_id         | integer                |
 phone_slot      | integer                | default 0
 Indexes:
    "call_record_pkey" PRIMARY KEY, btree (cntrct_id, log_date, log_time)
    "route_index" hash (route)
 Check constraints:
    "call_record_targ_pest_check" CHECK (targ_pest <= 100)
    "call_record_targ_pest_check1" CHECK (targ_pest >= 0)

          Table "public.per_call"
 Column  |         Type         | Modifiers
---------+----------------------+-----------
 dist_id | character varying(2) |
 route   | character varying(2) |
 type    | character(1)         |
 total   | integer              |

我需要从2个表中获取数据并将其打印在一个报告中。该报告应如下所示:

district | route | type | total | callbacks
         | 01    | T    | 12    | 5
         | 02    | P    | 0     | 0
         | 03    | P    | 3     | 1
2        | 01    | T    | 4     | 1
         | 02    | T    | 1     | 0
         | 03    | P    | 0     | 0
etc... (this is theoretical sample data)

所以,实质上我需要从表per_call中获取dist_id,route,type和count(*) 和call_record表中的call_backs计数

问题:循环遍历表格使得它变得非常缓慢。如何调整以下PSQL查询,以便我不必循环,我可以正确回显表格数据?

如果有任何不透明的情况,请告诉我,我会尽力澄清

   echo    '<table align="center" border = 2>
            <th>DISTRICT</th>
            <th>ROUTE</th>
            <th>TYPE</th>
            <th>TOTAL</th>
            <th>CALL BACKS</th>';


    $SQL = " SELECT per_call.dist_id, per_call.route, per_call.type, per_call.total
            FROM per_call, call_record
            WHERE TRUE  ";

    if($type == 'termite'){
            $SQL = $SQL." AND per_call.type  = 'T' ";
    }
    else{
            $SQL = $SQL." AND per_call.type = 'P' ";
    }
    $SQL = $SQL."   AND call_record.dist_id = per_call.dist_id
                    AND call_record.log_date >= '$startDate'
                    AND call_record.log_date <= '$endDate'
                    ORDER BY per_call.dist_id, per_call.route, per_call.type    ASC ";

    echo    $SQL;
                    /*AND call_record.log_date = '$startDate'
                    AND call_record.log_date = '$endDate'*/

    $Q = pg_query($connect,$SQL);
    while($row = pg_fetch_row($Q)){
            $dist = $row[0];
            $route = $row[1];
            $type = $row[2];
            $total = $row[3];

            echo '<tr>';
            echo '<td align="center">'.$dist.'</td>';
            echo '<td align="center">'.$route.'</td>';
            echo '<td align="center">'.$type.'</td>';
            echo '<td align="center">'.$total.'</td>';

            $SQL2 = "SELECT COUNT(*)
                    FROM call_record
                    WHERE dist_id = $dist
                    AND route = '$route'
                    AND substring(cntrct_id from 2 for 1) = '$type'
                    AND substring(call_regard_opt from 2 for 1) = '1'

                     ";
            $Q2 = pg_query($connect,$SQL2);
            $row2 = pg_fetch_row($Q2);

            $callbacks = $row2[0];

            echo '<td align="center">'.$callbacks.'</td>';

            echo '</tr>';
    }

    echo "</table>";

3 个答案:

答案 0 :(得分:2)

select pc.dist_id, pc.route, pc.type, pc.total,
    count(
        substring(cntrct_id from 2 for 1) = '$type'
        AND substring(call_regard_opt from 2 for 1) = '1'
        or null
    ) callbacks 
from
    per_call pc
    inner join
    call_record cr on cr.dist_id = pc.dist_id
where cr.log_date between '$startdate' and cr.log_date <= '$enddate'
group by pc.dist_id, pc.route, pc.type, pc.total
order by pc.dist_id, pc.route, pc.type asc

答案 1 :(得分:1)

除非索引问题,否则您的查询写得不好,因此从查询表单的角度来看,它无法真正优化。你可以这样做虽然更干​​净:

$SQL = "SELECT per_call.dist_id, per_call.route, per_call.type, per_call.total
  FROM per_call, call_record
 WHERE call_record.dist_id = per_call.dist_id
   AND per_call.type  = '".($type == 'termite' ? "T" : "P")."'
   AND call_record.log_date >= '$startDate'
   AND call_record.log_date <= '$endDate'
 ORDER BY per_call.dist_id, per_call.route, per_call.type"

无论如何,这仍然容易受到SQL注入攻击。尝试使用parameterized queries

答案 2 :(得分:1)

在任一表中dist_id上都没有任何索引,这会使您的加入速度变慢。在dist_id上添加索引,看看它有多大改进。

此外,循环中的查询将是您的死亡,因为您将要做很多很多查询。将内部查询处理到主查询中,以便只在数据库中执行一个查询。