Php MySQL性能-如何加速构建/烧毁图表的查询?

Php MySQL性能-如何加速构建/烧毁图表的查询?,php,mysql,database-performance,Php,Mysql,Database Performance,我正在用MySQL/PHP编写一个应用程序生成构建图和一个燃尽图,我使用NVD3.js生成它 我下面的代码每天循环使用我的数据集的从最小到最大的日期,可以对其进行筛选 到目前为止,我每天运行查询1次,我意识到这会增加巨大的延迟,大约10秒等待加载 如何更快地生成此数据? 调用代码 public function burnupAction() { $actionItemTable = $this->getActionItemTable(); $burn

我正在用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";
    }
组合图表代码

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";
    }

for($y=$minYear;$y查询的主要部分如下:

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;
此查询有一个缺点:每个日期扫描表actionitems

为了改进这一点,可以将查询编写为:

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;
这会给你每次约会的“裸体主义”

将@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);

如果您正在扫描表中的日期范围是我假设您有日期索引,则此索引将起作用。您可以做的是存储@csum值。您还可以在SQL中列出1或2个完整查询。我知道您的代码的作用,但在我的脑海中生成它并不是提供性能建议的最佳方法。请e following-感谢您的快速回复,我相信我还没有为我的查询设置索引,但如果这有帮助的话,我可以通过添加索引来加速。好的,我知道您做了什么。是的,这可以做得更快。索引将是一部分,另一部分是主查询。我将使用一个答案框来完成这一部分:请随意输入谢谢你的快速回复。让我们进行更改,我会向您汇报。另外,我的行数实际上是相反的,它远小于我生成的日期数。好的,1提示:对于数据库中没有数据的日期,这不会返回数据。所以当迭代这个集合时,要考虑到这一点。还要首先在mysql会话中检查您的查询结果和这些结果:如果其中有错误,可以节省您大量时间:)谢谢您的评论,我正在尝试让它生成所有没有任何值的日期,我认为这可能需要在代码中保留我的主循环。