Optimizing Yii2 performance

Diagram showing Yii2 performance optimization techniques

Навигация

2.1 General provisions for optimization at the framework level

Optimizing web application performance at the framework level is an important element in improving the overall performance of a web application. The Yii2 framework provides developers with a wide range of built-in tools designed to reduce server load, speed up request processing, and improve application responsiveness without making significant changes to the application structure.

In the Yii2 Application Development Cookbook, a separate chapter is devoted to optimizing application performance (“Performance Tuning”)1. This chapter discusses the following optimization methods: 1) following best practices; 2) acceleration of session processing; 3) use of dependencies and cache chains; 4) application profiling using Yii; 5) use of HTTP caching; 6) pooling and minimizing resources; 7) running Yii2 on HHVM.

The above list of ways to optimize the performance of web applications developed using the Yii2 framework is not exhaustive. In this chapter, we will look at the main optimization methods implemented by Yii2. We offer the following classification of such methods: configuration settings (chapter 2.2); caching (chapter 2.3); effective work with Active Record (chapter 2.4). In Chapter 2.5 of this WRC, we will consider in practice the effectiveness of optimizing application performance using the example of minification and combining CSS/JS through Asset Bundle.

2.2 Configuring Yii2

Yii2 framework configuration settings can affect application performance. As part of this WRC, we will consider the following ways to configure the Yii2 configuration: 1) enable production mode; 2) acceleration of session processing; 3) minification and merging of CSS/JS via Asset Bundle.

2.2.1 Enabling production mode

Yii2 supports two main modes: 1) dev – for development; 2) prod – for operation. In development mode, included: detailed error messages; logging; profiling; additional checks. In production mode, all these features are disabled or minimized, which reduces overhead and speeds up the application.

When YII_DEBUG is set to false, Yii disables trace-level logging and uses less error-handling code. Additionally, if YII_ENV is set to "prod", then the application will not load the Yii2 application debug panel (which also consumes resources). The debugging panel collects a large amount of service information: SQL queries; lead time; session data; logs In a work environment it is not needed and creates unnecessary burden. For these reasons, to optimize application performance, the literature recommends enabling production mode2.

2.2.2 Speeding up session processing

In most cases, standard PHP session handling is fine. There are at least two possible reasons why you might need to change the way sessions are handled: 1) when using multiple servers, you need to have a common session store for both servers; 2) PHP sessions use files by default, so maximum possible performance is limited by disk I/O; 3) PHP sessions by default block simultaneous storage of sessions.

To speed up session processing, it is recommended in the literature, for example, to add the following configuration to the /config/web.php file3:

'session' => [

'class' => \yii\web\CacheSession::class,

'cache' => 'sessionCache',

],

'sessionCache' => [

'class' => \yii\caching\MemCache::class,

],

2.2.3 Minification and bundling of CSS/JS via Asset Bundle

Front-end resources also affect performance. Asset Bundle allows you to: combine CSS and JavaScript files; minify the code; reduce the number of HTTP requests; speed up page loading. Especially important for mobile users and slow networks. If a web page contains many CSS and/or JavaScript files, it will open very slowly because the browser sends a large number of HTTP requests to download each file in separate threads.

To reduce the number of requests and connections, we can combine and compress multiple CSS/JavaScript files into one or more files in production, and then include these compressed files in the page instead of the original ones4. The main problem is that the web application sometimes includes many static files, for example: bootstrap.css, site.css, jquery.js, yii.js, bootstrap.js. In this case, the browser makes many HTTP requests, opens many connections, waits for each file to be downloaded. For these reasons, the page opens slowly.

In this case, to increase the speed of the application, in production mode (prod) you can: combine all CSS into one file; combine all JS into one file; remove extra spaces and comments (minification). As a result, the number of downloaded files will be significantly reduced (instead of 5-20 files there will be 1-2 files).

This is one of the key ways to speed up the frontend. Which will improve: the time when the user first sees any visual element of the page (First Paint or FP); the time when the site not only appeared, but also began to respond to user actions (Time to Interactive or TTI).

Assets in Yii2 are static resources: CSS; JavaScript; fonts; images. Yii manages them through AssetBundle. Before optimization, HTML contains many connections:

After optimization we get two files:

Result: fewer requests; faster loading; and, accordingly, performance improves. The example above uses the built-in yii asset tool, which: collects all AssetBundle dependencies; publishes files to /web/assets; unites them; minifies; creates a configuration for operating mode (prod).

First we run the command (php yii asset/template assets.php), which creates a configuration file (assets.php) containing a template for managing assets. Then we carry out the minification procedure itself, for which a special command is provided: php yii asset assets.php assets-prod.php.

And as a final step, in the configuration file config/web.php we add the following lines of code:

'assetManager' => [

'bundles' => YII_ENV_PROD

? require(__DIR__ . '/assets-prod.php')

: [],

],

The corresponding configuration change will allow you to automatically connect minified resources only in operation mode. As a result, in development mode (dev) we will use regular files (which can be conveniently modified), and in production mode (prod) we will use combined (minified) files that will load quickly. In addition, the yii asset tool: rewrites relative paths; correctly transfers fonts and static resources; takes into account dependencies between libraries.

2.3 Caching in Yii2

Caching is one of the most effective ways to improve performance, allowing you to save the results of resource-intensive operations and reuse them without re-executing them. Yii2 has an advanced caching system that supports various types of storage.

As long as PHP programs remain scripts that run, produce results, and die, the idea of caching computational results will remain relevant. The mathematical concept of memoization, implemented at the language runtime level, is ubiquitous in the PHP ecosystem, and the Yii framework supports a wide range of caching techniques to speed up programs.

Yii2 has the following four caching levels: 1) database query caching; 2) caching fragments of HTML pages; 3) caching the entire request to the server; 4) caching the HTTP response using some HTTP headers.

Before we look at all these features one by one, we need to know that Yii2 has a special caching component that underlies this mechanism5.

2.3.1 Using HTTP caching

Instead of implementing caching only on the server side, the Yii2 framework introduces the ability to use caching on the client side using special HTTP headers6. The Yii2 framework provides the ability to cache on the client side via HTTP headers: Last-Modified and ETag (that is, not a server cache as in Yii2 PageCache, but a browser mechanism). Optimization on the client side is discussed in detail in Chapter 4 of this WRC.

The browser stores the page as well as its metadata. If the page has not changed, the server does not resend it. Without an HTTP cache, each page refresh represents the execution of the following sequence of procedures: 1) the browser makes a request; 2) the server executes the code; 3) generates HTML; 4) sends a 200 OK response. The corresponding sequence of procedures is executed every time the application page is accessed, even if nothing has changed. If the page has not changed, then the server responds: “304 Not Modified” and does not send the page. In this case, time, traffic, load on the server, CPU and database are saved. Let's look at the features of the Last-Modified and ETag HTTP headers.

The use of the Last-Modified HTTP header (caching based on the resource modification time) is implemented using the yii\filters\HttpCache filter. For a list of articles, the last modified time value is determined as follows:

'lastModified' => function () {

return Article::find()->max('updated_at');

}

This approach means that the page is considered modified if the last update time of one of the articles changes. When initially accessing a resource, the server returns a response with a 200 OK status and a Last-Modified header containing the date the resource was last modified (Last-Modified: Thu, 21 Apr 2026 00:56:02 GMT). When accessing a resource again, the client (browser) sends the If-Modified-Since HTTP header to the server, containing the date of the last known modification of the resource. After updating the content, the time changes and for this reason the server sends the full page again, as well as a new Last-Modified.

The use of the HTTP header ETag (caching based on resource content) is used for individual pages, such as a specific article page. The ETag value is generated based on the resource content using the following construct:

'etagSeed' => function () {

return serialize([$article->title, $article->text]);

}

In this case, the server generates a unique resource identifier based on its content. The first time a resource is accessed, the server returns a response with a 200 OK status and an ETag header. When re-requesting, the client sends the server an If-None-Match header containing the previously received ETag value.

If the contents of the resource have not changed, the server returns a response with a 304 Not Modified status without a message body. If the article changes, a new ETag value is generated and the server returns the updated resource with a 200 OK status and the new header value.

Last-Modified is time-based, fast (requires less CPU load), but is time-dependent and is therefore believed to be less accurate with frequent changes. ETag is considered more accurate, depends on the content (if the content has changed, then the ETag will also change), can be used in relation to specific (single) resources, and not massively to all at once, can work without using timestamps (the date and time the file was modified), but requires large computing resources of the server.

2.3.2 DataCache, FragmentCache and PageCache

DataCache is designed for caching arbitrary data - calculation results, database selections, configuration data, etc. Yii2 supports several caching drivers, including the following: FileCache, RedisCache, MemCache.

FileCache stores data in files on disk. Easy to set up and does not require additional software. Suitable for small projects or resource-constrained environments. The advantages are ease of use, no need for third-party services, and resistance to server restarts. Among the disadvantages are the relatively low speed with a large number of files, as well as the load on the file system.

MemCache uses the server's RAM through the Memcached service and thus provides high access speed. The benefits include high performance and minimal latency. For these reasons, MemCache is most suitable for high-load systems. Disadvantages include that data is lost when the server is restarted, and Memcached installation is also required.

RedisCache works through the Redis system, which is a high-performance in-memory storage. The list of advantages includes high speed, support for complex data structures, as well as the ability to use both a cache and a database. The only drawback is the need to install and administer Redis.

FragmentCache is used to cache individual parts of the page (widgets, blocks, lists of data). This is especially useful if the page contains both static and dynamic content, for example, a list of popular products, a sidebar, a menu, a news block. FragmentCache allows you to update only the parts of the page that change, without affecting the rest of the markup.

PageCache caches the entire generated page. When contacting the user again, the finished HTML is returned to the user without executing the application logic. Can be used for pages with rarely changing content, public sections of the site, pages without personalization. PageCache can significantly reduce the load on the server, especially with a large number of similar requests.

2.3.3 Caching Active Record requests

Active Record in Yii2 supports caching of SQL query results. This allows you to avoid repeated calls to the database when executing identical queries. The corresponding caching mechanism works as follows: 1) an SQL query is executed; 2) the result is stored in the cache; 3) when the request is repeated, the data is retrieved from the cache. This optimization method is especially effective for directories, immutable data, and frequently used samples. Query caching significantly reduces the load on the database and speeds up system response.

Executing complex queries (for example, analytical ones), aggregating data, and generating reports can take considerable time. If such queries are executed frequently and the data changes infrequently, it makes sense to use caching. Yii2 implements the ability to cache query results at the application level.

Example of result caching:

$stats = Yii::$app->cache->getOrSet('salesStats', function () {

return (new \yii\db\Query())

->select(['COUNT(*) AS total', 'SUM(amount) AS sum'])

->from('orders')

->where(['status' => 'completed'])

->one();

}, 600);

In the example above, the cache is stored for 10 minutes, after which it will be recalculated.

SQL caching at the database component level:

$products = Yii::$app->db->cache(function ($db) {

return $db->createCommand(

'SELECT * FROM product WHERE status = 1'

)->queryAll();

}, 300);

The benefits of caching include reduced database load, faster application response, and increased resilience during peak loads.

2.3.4 Using cache dependencies and cache chains

When developing web applications, there are often situations in which it is not practical to cache data for a certain period of time because the relevant data can change at any time. The key problem in this case is that if you cache the page, for example, for 1 year, the data will not be updated, even if: 1) a new operation is added; 2) the article has changed; 3) the balance has changed.

Cache Dependency is a condition under which a cache is considered stale. When the cache is first created, the page itself and the dependency control value are saved. When requesting again: the dependency is checked again; if the value has changed, then the cache is recreated, and if not, then the old cache is used.

A caching chain is a union of several dependencies. The cache will be updated if at least one of the elements in this chain changes. In the literature, an example of the simultaneous use of “DbDependency” and “TagDependency”7 is considered. DbDependency – when a new record is added to the table, the cache will be updated automatically. TagDependency – dependency by tag (must be invalidated manually, for example, when saving the text of an article). Yii2's support for cache dependencies and caching chains allows you to cache the entire page and still always get the latest data when refreshing.

2.4 Working effectively with Active Record

Active Record is a convenient but resource-intensive tool for working with a database. If used incorrectly, this object can become a performance bottleneck in a web application. When working with connections between models, two main approaches to loading data are used: Lazy Loading and Eager Loading.

Lazy loading means that the associated data is loaded only the first time it is accessed. This approach can lead to the N+1 query problem, where a separate database query is executed for each master record, which slows down the application when there is a large amount of data.

In contrast to this approach, greedy loading allows you to preload related data in a single query using a JOIN. This reduces the number of SQL queries and shortens the execution time, making the server load more predictable. This approach provides better performance when working with lists and data tables.

Therefore, greedy loading is often used to display large amounts of related data in tables and lists. This approach allows you to speed up the application and reduce the number of redundant queries to the database.

When working with large tables, loading all records into memory at once can lead to memory overflow and application crash. To avoid such problems, the batch() and each() methods are used to process data in parts. The batch() method returns sets of records of a given size, while each() iterates through records one at a time, loading them in batches.

The use of these techniques allows you to significantly save RAM and provides the ability to process a large amount of data without overloading the system. This approach allows you to create web applications that are more resistant to heavy loads, as well as work efficiently with large volumes of data.

This is of particular importance when performing background tasks, migrating data, generating reports, as well as importing and exporting information. Using batch processing in these scenarios ensures stable operation and optimal use of system resources.


  1. Bogdanov A., Eliseev D. Yii2 Application Development Cookbook. – Packt Publishing, 2016. 

  2. Bogdanov A., Eliseev D. Yii2 Application Development Cookbook. – Packt Publishing, 2016. 

  3. Bogdanov A., Eliseev D. Yii2 Application Development Cookbook. – Packt Publishing, 2016. 

  4. Bogdanov A., Eliseev D. Yii2 Application Development Cookbook. – Packt Publishing, 2016. 

  5. Safronov M. Development of web applications in Yii 2 – M.: DMK Press, 2015. 

  6. Bogdanov A., Eliseev D. Yii2 Application Development Cookbook. – Packt Publishing, 2016. 

  7. Bogdanov A., Eliseev D. Yii2 Application Development Cookbook. – Packt Publishing, 2016.