在InnoDB表上使用ZF2 Paginator计算Count()的糟糕表现

jcq*_*jcq 6 mysql innodb zend-framework2

我试图在一些大型(大约1000万,最差情况下没有搜索过滤器)记录集上使用ZF2 Paginator.我的表格是InnoDB格式,据我所知,这些格式并没有作为元数据的一部分.

我意识到我可以扩展Zend\Paginator\Adapter\DbSelect类并实现我自己的count()方法,该方法使用我手动存储在另一个表中的计数数据,但我不确定如何存储所有可能排列的计数可能会进行的搜索.

默认的ZF2 DbSelect适配器使用此方法:

<?php
public function count()
{
    if ($this->rowCount !== null) {
        return $this->rowCount;
    }

    $select = clone $this->select;
    $select->reset(Select::LIMIT);
    $select->reset(Select::OFFSET);
    $select->reset(Select::ORDER);

    $countSelect = new Select;
    $countSelect->columns(array('c' => new Expression('COUNT(1)')));
    $countSelect->from(array('original_select' => $select));

    $statement = $this->sql->prepareStatementForSqlObject($countSelect);
    $result    = $statement->execute();
    $row       = $result->current();

    $this->rowCount = $row['c'];

    return $this->rowCount;
}
?>
Run Code Online (Sandbox Code Playgroud)

这是一个方法为我生成的一个非常简单的示例查询:

SELECT
    COUNT(1) AS `c`
FROM
    (
        SELECT
            `contacts`.`id` AS `id`,
            `contacts`.`firstname` AS `firstname`,
            `contacts`.`middlename` AS `middlename`,
            `contacts`.`lastname` AS `lastname`,
            `contacts`.`gender` AS `gender`
        FROM
            `contacts`
        WHERE
            `contacts`.`trash` = '0'
    ) AS `original_select`
Run Code Online (Sandbox Code Playgroud)

我不确定MyISAM表的性能如何,但由于它占用了运行它的Amazon RDS(25GB,db.m1.small)实例上的所有可用空间,因此我失败了.作为比较,仅运行内部(原始)查询,它在100秒内完成(当然不好)并返回739万条记录.

这是来自内部查询的EXPLAIN(由于RDS服务器上的磁盘空间,计数器上的EXPLAIN也会死掉):

+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
| id | select_type | table    | type | possible_keys | key   | key_len | ref   | rows    | Extra |
+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
| 1  | SIMPLE      | contacts | ref  | trash         | trash | 1       | const | 3441317 |       |
+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+
1 rows in set (0.04 sec)

有什么可以做的更好地调整这个吗?ZF2 Paginator处理的方式是否与InnoDB的工作方式在某种程度上不兼容?如果我们允许搜索数据库中的大多数字段,其他人如何处理所有可能的查询的缓存计数?

提前致谢...

Hac*_*man 1

如果您改用此查询:

SELECT c from
(    
  SELECT COUNT(1) AS c
  from contacts
  where trash = '0'
) AS original_select
Run Code Online (Sandbox Code Playgroud)