Próbuję użyć Paginatora ZF2 na niektórych dużych zestawach rekordów (około 10 milionów w najgorszym przypadku bez filtra wyszukiwania). Moje tabele są w formacie InnoDB, co, jak rozumiem, nie obejmuje dokładnego liczenia jako części metadanych.Abysmal Performance for Count() za pomocą Paginarza ZF2 na tabelach InnoDB
Zdaję sobie sprawę, że mogę rozszerzyć klasę Zend \ Paginator \ Adapter \ DbSelect i zaimplementować własną metodę count(), która wykorzystuje dane liczbowe, które ręcznie zapisuję w innej tabeli, ale nie jestem pewien, jak przechowywać liczniki dla wszystkie możliwe permutacje wyszukiwań, które można wykonać.
Domyślna ZF2 DbSelect adapter używa tej metody:
<?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;
}
?>
Oto bardzo prosty przykład kwerendy, która metoda daje mi:
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`
Nie jestem pewien, co wydajność byłaby na MyISAM tabele, ale to mi się nie uda, ponieważ pochłania całą wolną przestrzeń w instancji Amazon RDS (25 GB, db.m1.small), na której jest uruchomiona. Dla porównania, uruchomienie tylko wewnętrznego (oryginalnego) zapytania kończy się w ciągu 100 sekund (z pewnością nie jest dobre) i zwraca 7.39 milionów rekordów.
Oto EXPLAIN z kwerendy wewnętrznej (wyjaśniania na hrabiego też umiera z powodu przestrzeni dyskowej na serwerze RDS):
+----+-------------+----------+------+---------------+-------+---------+-------+---------+-------+ | 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)
Czy jest coś, co można zrobić, aby dostroić to lepiej? Czy sposób, w jaki Paginator obsługuje ZF2, jest niekompatybilny w taki sposób, w jaki robi to InnoDB? W jaki sposób inni będą obsługiwać zapisy w pamięci podręcznej wszystkich możliwych zapytań, jeśli zezwalamy na wyszukiwanie w większości pól w bazie danych?
góry dzięki ...
Ten problem jest związany z InnoDB, MyISAM nie ma tego problemu, ponieważ śledzi liczbę wierszy w tabeli w swoich metadanych. Najlepiej jest po prostu poprawić zapytanie w interfejsie bazy danych i zobaczyć, jaki jest jego efekt. Zamiast COUNT (1) możesz wypróbować na przykład COUNT (id) lub powiedzieć MySQL, aby używał określonego indeksu używając mysql> select count (1) from ... use index (your_index) – Ruben
** COUNT (1) **: 15 min 36sek; ** COUNT (identyfikator) **: 18 minut 8,83 s – jcq