我试图在某些大型(大约1000万,最差情况下没有搜索过滤器)记录集上使用ZF2 Paginator。我的表格是InnoDB格式,据我所知,这些格式并没有作为元数据的一部分。
我意识到我可以扩展Zend \ Paginator \ Adapter \ DbSelect类并实现我自己的count()方法,该方法使用我手动存储在另一个表中的计数数据,但我不确定如何为所有存储计数可能进行的搜索的可能排列。
默认ZF2 DbSelect adapter使用此方法:
<?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;
}
?>
以下是该方法为我生成的一个非常简单的示例查询:
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`
我不确定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的工作方式在某种程度上不兼容?如果我们允许搜索数据库中的大多数字段,其他人如何处理所有可能查询的缓存计数?
提前致谢...
答案 0 :(得分:2)
您不需要从原始查询中选择 - 这会消耗您的内存/磁盘空间!
SELECT count( 1 ) AS `c`
FROM (
SELECT 1
FROM `contacts`
WHERE `trash` = 0
) AS `original_select`
除此之外:
假设垃圾桶只是一个布尔值,请将其设为布尔值不可为空的列,并搜索int或布尔值为true / false
ALTER TABLE `contacts` CHANGE `trash` `trash` TINYINT( 1 ) NOT NULL
请务必为垃圾栏编制索引
ALTER TABLE `contacts` ADD INDEX `TRASH` ( `trash` )
更多:
大型结果集的分页不一定需要精确计数:假设我们每页显示100个条目,我们不需要100000个单页N个按钮。而是使用偏移量和限制来计算页面,只显示单个按钮,例如上一页/后十页,并将其与一些“show next / prev 10 pages”按钮结合起来。
当您需要“转到最后一页”的可能性时,为什么不使用DESC命令之类的东西来实现类似的目标。
是否有人会通过你的10米行分页?也许提供高级过滤器来帮助用户找到他需要的东西。
答案 1 :(得分:0)
如果您改用此查询:
SELECT c from
(
SELECT COUNT(1) AS c
from contacts
where trash = '0'
) AS original_select