Magento has a built-in cache. In version 1.5.0.1 Magento added a Full Page Cache option to Magento which gives us the ability to use holepunch techniques to cache blocks. This section here doesn't deal with the full page cache at all, rather just uses the standard Magento cache and we add the ability for Magento to cache category lists

In the below examples, we haven't yet added the caching. We use the following (example) command from Apache Benchmark on the local machine the tests are being run on to run the tests, which eliminates network contention

ab -c 5 -n 100 http://www.testdomain.com/category

Before: Stats Showing # of Database Queries & Time Taken for 100 requests

Below, you can see that we had 153 requests to the database. The total time to run the tests was 19.452 seconds resulting in 5.14 requests per second. The median wait time to process each request was 666 milliseconds

Speedup Magento Category Listing
Concurrency Level:      5
Time taken for tests:   19.452007 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      12481500 bytes
HTML transferred:       12433700 bytes
Requests per second:    5.14 [#/sec] (mean)
Time per request:       972.600 [ms] (mean)
Time per request:       194.520 [ms] (mean, across all concurrent requests)
Transfer rate:          626.57 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       3
Processing:   608  961 579.6    700    4578
Waiting:      580  924 581.1    666    4542
Total:        608  961 579.7    700    4579

Percentage of the requests served within a certain time (ms)
  50%    700
  66%    851
  75%   1053
  80%   1160
  90%   1670
  95%   2258
  98%   2778
  99%   4579
 100%   4579 (longest request)

Below are the database statistics provided by the profiler

Executed 153 queries in 0.0114271640778 seconds
Average query length: 7.46873469135E-5 seconds
Queries per second: 13389.1487826
Longest query length: 0.000326871871948

After: Stats Showing # of Database Queries & Time Taken for 100 requests

Now we have made the changes, you can see that we had 64 requests to the database. The total time to run the tests was 12.546 seconds resulting in 7.97 requests per second. The median wait time to process each request was 439 milliseconds.

Speedup Magento Category Listing
Concurrency Level:      5
Time taken for tests:   12.546279 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      12481500 bytes
HTML transferred:       12433700 bytes
Requests per second:    7.97 [#/sec] (mean)
Time per request:       627.314 [ms] (mean)
Time per request:       125.463 [ms] (mean, across all concurrent requests)
Transfer rate:          971.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:   409  619 339.7    474    2258
Waiting:      383  583 339.5    439    2222
Total:        409  619 339.7    474    2258

Percentage of the requests served within a certain time (ms)
  50%    474
  66%    541
  75%    625
  80%    715
  90%    922
  95%   1518
  98%   1928
  99%   2258
 100%   2258 (longest request)

Below are the database statistics provided by the profiler

Executed 64 queries in 0.00508761405945 seconds
Average query length: 7.94939696789E-5 seconds
Queries per second: 12579.5705516
Longest query length: 0.000263929367065

This equates to a 50% speedup for category listings

How to Make the Code Changes

We need to override the core List.php file to make these changes. To do this via SSH:

    mkdir -p app/code/local/Mage/Catalog/Block/Product/
    cp app/code/core/Mage/Catalog/Block/Product/List.php app/code/local/Mage/Catalog/Block/Product/List.php

This overrides our core product list file with our own version that we can now modify accordingly. Now modify the file like so:

    app/code/local/Mage/Catalog/Block/Product/List.php
class Mage_Catalog_Block_Product_List extends Mage_Catalog_Block_Product_Abstract
{   
    /**
     * Default toolbar block name
     *
     * @var string
     */
    protected $_defaultToolbarBlock = 'catalog/product_list_toolbar';
to be
class Mage_Catalog_Block_Product_List extends Mage_Catalog_Block_Product_Abstract
{   

    protected function _construct()
    {   
        $this->addData(array('cache_lifetime'    =>  9999999999,));
    }

    public function getCacheTags()
    {   
        return array(Mage_Catalog_Model_Product::CACHE_TAG);
    }

    public function getCacheKey()
    {   
        return $this->getRequest()->getRequestUri();
    }
    /**
     * Default toolbar block name
     *
     * @var string
     */
    protected $_defaultToolbarBlock = 'catalog/product_list_toolbar';
Credit for much of this goes to Chris Farley on Magento Forums