mirror of
				https://github.com/yiisoft/yii2.git
				synced 2025-11-04 14:46:19 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			221 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
Performance Tuning
 | 
						|
==================
 | 
						|
 | 
						|
There are many factors affecting the performance of your Web application. Some are environmental, some are related 
 | 
						|
with your code, while some others are related with Yii itself. In this section, we will enumerate most of these
 | 
						|
factors and explain how you can improve your application performance by adjusting these factors.
 | 
						|
 | 
						|
 | 
						|
## Optimizing your PHP Environment <span id="optimizing-php"></span>
 | 
						|
 | 
						|
A well configured PHP environment is very important. In order to get maximum performance,
 | 
						|
 | 
						|
- Use the latest stable PHP version. Major releases of PHP may bring significant performance improvements.
 | 
						|
- Enable bytecode caching with [Opcache](http://php.net/opcache) (PHP 5.5 or later) or [APC](http://ru2.php.net/apc) 
 | 
						|
  (PHP 5.4 or earlier). Bytecode caching avoids the time spent in parsing and including PHP scripts for every
 | 
						|
  incoming request.
 | 
						|
- [Tune `realpath()` cache](https://github.com/samdark/realpath_cache_tuner).
 | 
						|
 | 
						|
 | 
						|
## Disabling Debug Mode <span id="disable-debug"></span>
 | 
						|
 | 
						|
When running an application in production, you should disable debug mode. Yii uses the value of a constant
 | 
						|
named `YII_DEBUG` to indicate whether debug mode should be enabled. When debug mode is enabled, Yii
 | 
						|
will take extra time to generate and record debugging information.
 | 
						|
 | 
						|
You may place the following line of code at the beginning of the [entry script](structure-entry-scripts.md) to
 | 
						|
disable debug mode:
 | 
						|
 | 
						|
```php
 | 
						|
defined('YII_DEBUG') or define('YII_DEBUG', false);
 | 
						|
```
 | 
						|
 | 
						|
> Info: The default value of `YII_DEBUG` is false. So if you are certain that you do not change its default
 | 
						|
  value somewhere else in your application code, you may simply remove the above line to disable debug mode. 
 | 
						|
  
 | 
						|
 | 
						|
## Using Caching Techniques <span id="using-caching"></span>
 | 
						|
 | 
						|
You can use various caching techniques to significantly improve the performance of your application. For example,
 | 
						|
if your application allows users to enter text in Markdown format, you may consider caching the parsed Markdown
 | 
						|
content to avoid parsing the same Markdown text repeatedly in every request. Please refer to 
 | 
						|
the [Caching](caching-overview.md) section to learn about the caching support provided by Yii.
 | 
						|
 | 
						|
 | 
						|
## Enabling Schema Caching <span id="enable-schema-caching"></span>
 | 
						|
 | 
						|
Schema caching is a special caching feature that should be enabled whenever you are using [Active Record](db-active-record.md).
 | 
						|
As you know, Active Record is intelligent enough to detect schema information (e.g. column names, column types, constraints)
 | 
						|
about a DB table without requiring you to manually describe them. Active Record obtains this information by executing 
 | 
						|
extra SQL queries. By enabling schema caching, the retrieved schema information will be saved in the cache and reused
 | 
						|
in future requests.
 | 
						|
 | 
						|
To enable schema caching, configure a `cache` [application component](structure-application-components.md) to store
 | 
						|
the schema information and set [[yii\db\Connection::enableSchemaCache]] to be `true` in the [application configuration](concept-configurations.md):
 | 
						|
 | 
						|
```php
 | 
						|
return [
 | 
						|
    // ...
 | 
						|
    'components' => [
 | 
						|
        // ...
 | 
						|
        'cache' => [
 | 
						|
            'class' => 'yii\caching\FileCache',
 | 
						|
        ],
 | 
						|
        'db' => [
 | 
						|
            'class' => 'yii\db\Connection',
 | 
						|
            'dsn' => 'mysql:host=localhost;dbname=mydatabase',
 | 
						|
            'username' => 'root',
 | 
						|
            'password' => '',
 | 
						|
            'enableSchemaCache' => true,
 | 
						|
 | 
						|
            // Duration of schema cache.
 | 
						|
            'schemaCacheDuration' => 3600,
 | 
						|
 | 
						|
            // Name of the cache component used to store schema information
 | 
						|
            'schemaCache' => 'cache',
 | 
						|
        ],
 | 
						|
    ],
 | 
						|
];
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
## Combining and Minimizing Assets <span id="optimizing-assets"></span>
 | 
						|
 | 
						|
A complex Web page often includes many CSS and/or JavaScript asset files. To reduce the number of HTTP requests 
 | 
						|
and the overall download size of these assets, you should consider combining them into one single file and
 | 
						|
compressing it. This may greatly improve the page loading time and reduce the server load. For more details,
 | 
						|
please refer to the [Assets](structure-assets.md) section.
 | 
						|
 | 
						|
 | 
						|
## Optimizing Session Storage <span id="optimizing-session"></span>
 | 
						|
 | 
						|
By default session data are stored in files. The implementation is locking a file from opening a session to the point it's
 | 
						|
closed either by `session_write_close()` (in Yii it could be done as `Yii::$app->session->close()`) or at the end of request.
 | 
						|
While session file is locked all other requests which are trying to use the same session are blocked i.e. waiting for the
 | 
						|
initial request to release session file. This is fine for development and probably small projects. But when it comes 
 | 
						|
to handling massive concurrent requests, it is better to use more sophisticated storage, such as database. Yii supports
 | 
						|
a variety of session storage out of box. You can use these storage by configuring the `session` component in the
 | 
						|
[application configuration](concept-configurations.md) like the following,
 | 
						|
 | 
						|
```php
 | 
						|
return [
 | 
						|
    // ...
 | 
						|
    'components' => [
 | 
						|
        'session' => [
 | 
						|
            'class' => 'yii\web\DbSession',
 | 
						|
 | 
						|
            // Set the following if you want to use DB component other than
 | 
						|
            // default 'db'.
 | 
						|
            // 'db' => 'mydb',
 | 
						|
 | 
						|
            // To override default session table, set the following
 | 
						|
            // 'sessionTable' => 'my_session',
 | 
						|
        ],
 | 
						|
    ],
 | 
						|
];
 | 
						|
```
 | 
						|
 | 
						|
The above configuration uses a database table to store session data. By default, it will use the `db` application
 | 
						|
component as the database connection and store the session data in the `session` table. You do have to create the
 | 
						|
`session` table as follows in advance, though,
 | 
						|
 | 
						|
```sql
 | 
						|
CREATE TABLE session (
 | 
						|
    id CHAR(40) NOT NULL PRIMARY KEY,
 | 
						|
    expire INTEGER,
 | 
						|
    data BLOB
 | 
						|
)
 | 
						|
```
 | 
						|
 | 
						|
You may also store session data in a cache by using [[yii\web\CacheSession]]. In theory, you can use any supported
 | 
						|
[cache storage](caching-data.md#supported-cache-storage). Note, however, that some cache storage may flush cached data
 | 
						|
when the storage limit is reached. For this reason, you should mainly use those cache storage that do not enforce
 | 
						|
storage limit.
 | 
						|
 | 
						|
If you have [Redis](http://redis.io/) on your server, it is highly recommended you use it as session storage by using
 | 
						|
[[yii\redis\Session]].
 | 
						|
 | 
						|
 | 
						|
## Optimizing Databases <span id="optimizing-databases"></span>
 | 
						|
 | 
						|
Executing DB queries and fetching data from databases are often the main performance bottleneck in
 | 
						|
a Web application. Although using [data caching](caching-data.md) techniques may alleviate the performance hit,
 | 
						|
it does not fully solve the problem. When the database contains enormous amounts of data and the cached data is invalid, 
 | 
						|
fetching the latest data could be prohibitively expensive without proper database and query design.
 | 
						|
 | 
						|
A general technique to improve the performance of DB queries is to create indices for table columns that
 | 
						|
need to be filtered by. For example, if you need to look for a user record by `username`, you should create an index
 | 
						|
on `username`. Note that while indexing can make SELECT queries much faster, it will slow down INSERT, UPDATE and DELETE queries.
 | 
						|
 | 
						|
For complex DB queries, it is recommended that you create database views to save the query parsing and preparation time.
 | 
						|
 | 
						|
Last but not least, use `LIMIT` in your `SELECT` queries. This avoids fetching an overwhelming amount of data from the database
 | 
						|
and exhausting the memory allocated to PHP.
 | 
						|
 | 
						|
 | 
						|
## Using Plain Arrays <span id="using-arrays"></span>
 | 
						|
 | 
						|
Although [Active Record](db-active-record.md) is very convenient to use, it is not as efficient as using plain arrays
 | 
						|
when you need to retrieve a large amount of data from database. In this case, you may consider calling `asArray()`
 | 
						|
while using Active Record to query data so that the retrieved data is represented as arrays instead of bulky Active
 | 
						|
Record objects. For example,
 | 
						|
 | 
						|
```php
 | 
						|
class PostController extends Controller
 | 
						|
{
 | 
						|
    public function actionIndex()
 | 
						|
    {
 | 
						|
        $posts = Post::find()->limit(100)->asArray()->all();
 | 
						|
        
 | 
						|
        return $this->render('index', ['posts' => $posts]);
 | 
						|
    }
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
In the above code, `$posts` will be populated as an array of table rows. Each row is a plain array. To access
 | 
						|
the `title` column of the i-th row, you may use the expression `$posts[$i]['title']`.
 | 
						|
 | 
						|
You may also use [DAO](db-dao.md) to build queries and retrieve data in plain arrays. 
 | 
						|
 | 
						|
 | 
						|
## Optimizing Composer Autoloader <span id="optimizing-autoloader"></span>
 | 
						|
 | 
						|
Because Composer autoloader is used to include most third-party class files, you should consider optimizing it
 | 
						|
by executing the following command:
 | 
						|
 | 
						|
```
 | 
						|
composer dumpautoload -o
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
## Processing Data Offline <span id="processing-data-offline"></span>
 | 
						|
 | 
						|
When a request involves some resource intensive operations, you should think of ways to perform those operations
 | 
						|
in offline mode without having users wait for them to finish.
 | 
						|
 | 
						|
There are two methods to process data offline: pull and push. 
 | 
						|
 | 
						|
In the pull method, whenever a request involves some complex operation, you create a task and save it in a persistent 
 | 
						|
storage, such as database. You then use a separate process (such as a cron job) to pull the tasks and process them.
 | 
						|
This method is easy to implement, but it has some drawbacks. For example, the task process needs to periodically pull
 | 
						|
from the task storage. If the pull frequency is too low, the tasks may be processed with great delay, but if the frequency
 | 
						|
is too high, it will introduce high overhead.
 | 
						|
 | 
						|
In the push method, you would use a message queue (e.g. RabbitMQ, ActiveMQ, Amazon SQS, etc.) to manage the tasks. 
 | 
						|
Whenever a new task is put on the queue, it will initiate or notify the task handling process to trigger the task processing.
 | 
						|
 | 
						|
 | 
						|
## Performance Profiling <span id="performance-profiling"></span>
 | 
						|
 | 
						|
You should profile your code to find out the performance bottlenecks and take appropriate measures accordingly.
 | 
						|
The following profiling tools may be useful:
 | 
						|
 | 
						|
- [Yii debug toolbar and debugger](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md)
 | 
						|
- [Blackfire](https://blackfire.io/)
 | 
						|
- [XHProf](http://www.php.net/manual/en/book.xhprof.php)
 | 
						|
- [XDebug profiler](http://xdebug.org/docs/profiler)
 | 
						|
 | 
						|
## Prepare application for scaling
 | 
						|
 | 
						|
When nothing helps you may try making your application scalabe. A good introduction is provided in [Configuring a Yii2 Application for an Autoscaling Stack](https://github.com/samdark/yii2-cookbook/blob/master/book/scaling.md). For further reading you may refer to [Web apps performance and scaling](http://thehighload.com/).
 |