Difference between getSize() and count() on collection
Most (if not all) the collections extend Varien_Data_Collection_Db
. Here are the 2 methods from this class
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
}
return intval($this->_totalRecords);
}
public function count() //inherited from Varien_Data_Collection
{
$this->load();
return count($this->_items);
}
There is a difference. For getSize()
the collection is not loaded. For count()
it is.
Usually collection models use the same getSize()
method as above and only override getSelectCountSql()
.
In getSelectCountSql()
the limit is reset in order to get the total number of records available for the set filters (where
statement).
See how the getSelectCountSql()
works
public function getSelectCountSql()
{
$this->_renderFilters();
$countSelect = clone $this->getSelect();
$countSelect->reset(Zend_Db_Select::ORDER);
$countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
$countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
$countSelect->reset(Zend_Db_Select::COLUMNS);
$countSelect->columns('COUNT(*)');
return $countSelect;
}
Be careful. This is correct, but the methods are overwritten in Varien_Data_Collection_Db
as described by Marius
Just have a look into
// \Varien_Data_Collection::getSize
public function getSize()
{
$this->load();
if (is_null($this->_totalRecords)) {
$this->_totalRecords = count($this->getItems());
}
return intval($this->_totalRecords);
}
// \Varien_Data_Collection::count
public function count()
{
$this->load();
return count($this->_items);
}
So it should on this low level be the same. Both methods load the collection and count the items.
UPDATE
Oh I see a problem: getSize() caches the _totalRecords, this means it is not recalculated. Check where _totalRecords
is set?
This answer shows up in google for "magento getSize wrong" and similar searches so I would like to add a possible scenario that might be useful to someone
When you have a group statement in your query and you do a
SELECT COUNT(DISTINCT e.entity_id) ... GROUP BY ( at_id_art.value )
Mysql will return a count for EACH of the groups, so Varien_Data_Collection_Db::getSize() will return the wrong answer, this is because this function fetches the first row:
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
}
return intval($this->_totalRecords);
}
When it populates
$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
It selects the first row and therefore returns the total of the first group as the total size.
I ended up coming up with this code to count, based on the unique values of the attributes in my query.
$select = clone $collection->getSelect();
$group = $select->getPart(Zend_Db_Select::GROUP);
$select->reset(Zend_Db_Select::GROUP)->reset(Zend_Db_Select::COLUMNS)->columns("COUNT(DISTINCT {$group[0]})");
$totalCount = $collection->getConnection()->fetchOne($select);