MySQL性能 - 如何加速查询Build-Up / Burn-Down Chart?

时间:2015-07-17 15:58:55

标签: php mysql database-performance

我正在研究应用程序生成构建和MySQL / PHP中的燃尽图表,我用它来生成NVD3.js

下面的代码循环播放我的数据集的最小到最大日期的每一天,可以过滤。

到目前为止,我每天都会运行1次查询,我意识到这可能会增加大量延迟,等待加载大约需要10秒。

如何更快地生成此数据?

调用代码

public function burnupAction()
    {
        $actionItemTable = $this->getActionItemTable();
        $burnUp =  array('TotalActionItems' => $actionItemTable->getBurnup('AssignedDate'),
                         'ECDItems' => $actionItemTable->getBurnup('ECD'),
                         'OriginalDueItems' => $actionItemTable->getBurnup('DueDate'),
                         'ActualOpenItems' => $actionItemTable->getBurnup('ClosedDate'));
        $this->response->setContent(json_encode($burnUp));
        return $this->response;
    }

构建图表代码

for ($y = $minYear; $y <= $maxYear; $y++)
{
        if ($y == $minYear)
            $startMonth = $minMonth;
        else
            $startMonth = 1;

        if ($y == $maxYear)
            $finishMonth = $maxMonth;
        else
            $finishMonth = 12;


        for ($m = $startMonth; $m <= $finishMonth; $m++)
        {                       
            if ($m < 10)
            {
                $month = "0$m";
            }
            else 
            {
                $month = "$m";
            }
            $monthStr = $this->getMonth($m);


            for ($d = 1; $d <= 31; $d++)
            {
                    if ($d< 10)
                    {
                        $day = "0$d";
                    }
                    else 
                    {
                        $day = "$d";
                    }

                    $dt = "$monthStr $day $y";
                    $start = "$y-$month-$day";
                    $end = "$y-$month-$day";

                    $where = $this->filterString();
                    $filtered = "SELECT * FROM actionitems " . $where;

                    if ($field == 'AssignedDate')
                    {
                        array_push($subsel, "(select '$dt' as AssignedDate, sum(case when AssignedDate Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)");
                    }
                    if ($field == 'ECD')
                    {
                        array_push($subsel, "(select '$dt' as ECD, sum(case when ECD Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)");
                    }
                    if ($field == 'DueDate')
                    {
                        array_push($subsel, "(select '$dt' as DueDate, sum(case when DueDate Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from ($filtered) s)");
                    }
                    if ($field == 'ClosedDate')
                    {
                        array_push($subsel, "(select '$dt' as ClosedDate, sum(case when ClosedDate Between '$start' and '$end' then 1 else 0 end) as 'NumActionItems' from  ($filtered) s)");
                    }
            }
        }
    }

    if (count($subsel) == 0)
        return array();


    $sub = join(" union all ", $subsel);

    if ($field == 'AssignedDate')
    {
        $sql = "select AssignedDate, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t";
    }
    if ($field == 'ECD')
    {
        $sql = "select ECD, NumActionItems as ECDItems, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t";
    }
    if ($field == 'DueDate')
    {
        $sql = "select DueDate, NumActionItems as OriginalDueItems, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t";
    }
    if ($field == 'ClosedDate')
    {
        $sql = "select ClosedDate, NumActionItems as AcutalClosedItems, (@csum:= @csum + NumActionItems) as TotalActionItems from ($sub) t";
    }

生成的购物车(顶部积聚/底部燃尽)

Buildup/Burdown Charts

1 个答案:

答案 0 :(得分:1)

您的查询的主要部分是:

SELECT 'Mar 01 2015' AS AssignedDate,
            Sum(CASE
                  WHEN assigneddate BETWEEN '2015-03-01' AND '2015-03-01'
                THEN 1
                  ELSE 0
                end)      AS 'NumActionItems'
     FROM   (SELECT *
             FROM   actionitems) s;

此查询有一个缺点:每个日期都会扫描表格操作项。

为了改善这一点,查询可以写成:

SELECT 'Mar 01 2015' AS AssignedDate,
            COUNT(*) AS 'NumActionItems'
     FROM actionitems
     WHERE assigneddate BETWEEN '2015-03-01' AND '2015-03-01';

这仍然不漂亮,因此需要下一步: 所有日期的替代方案可以是:

SELECT assigneddate,
            COUNT(*) AS 'NumActionItems'
     FROM actionitems
     WHERE assigneddate BETWEEN '2015-03-01' AND '2015-03-30'
     GROUP BY assigndate;

这会给你“NumActionItems&#39;每个日期。

将@csum添加为外部查询:

SELECT assigneddate,
   ( @csum := @csum + numactionitems ) AS TotalActionItems 
FROM (    SELECT assigneddate,
            COUNT(*) AS 'NumActionItems'
     FROM actionitems
     WHERE assigneddate BETWEEN '2015-03-01' AND '2015-03-30'
     GROUP BY assigndate) a

应该给出相同的结果。

同时添加索引:

CREATE INDEX idx_ai_nn_1 ON actionitems(assigneddate);

如果您扫描表格的日期范围是&lt;&lt;小于您选择的行数。