29 changed files with 223 additions and 10 deletions
			
			
		| @ -0,0 +1,181 @@ | ||||
| Performance Tuning | ||||
| ================== | ||||
| 
 | ||||
| Application performance consists of two parts. First is the framework performance | ||||
| and the second is the application itself. Yii has a pretty low performance impact | ||||
| on your application out of the box and can be fine-tuned further for production | ||||
| environment. As for the application, we'll provide some of the best practices | ||||
| along with examples on how to apply them to Yii. | ||||
| 
 | ||||
| Preparing framework for production | ||||
| ---------------------------------- | ||||
| 
 | ||||
| ### Disabling Debug Mode | ||||
| 
 | ||||
| First thing you should do before deploying your application to production environment | ||||
| is to disable debug mode. A Yii application runs in debug mode if the constant | ||||
| `YII_DEBUG` is defined as `true` in `index.php` so to disable debug the following | ||||
| should be in your `index.php`: | ||||
| 
 | ||||
| ```php | ||||
| defined('YII_DEBUG') or define('YII_DEBUG', false); | ||||
| ``` | ||||
| 
 | ||||
| Debug mode is very useful during development stage, but it would impact performance | ||||
| because some components cause extra burden in debug mode. For example, the message | ||||
| logger may record additional debug information for every message being logged. | ||||
| 
 | ||||
| ### Enabling PHP opcode cache | ||||
| 
 | ||||
| Enabling the PHP opcode cache improves any PHP application performance and lowers | ||||
| memory usage significantly. Yii is no exception. It was tested with | ||||
| [APC PHP extension](http://php.net/manual/en/book.apc.php) that caches | ||||
| and optimizes PHP intermediate code and avoids the time spent in parsing PHP | ||||
| scripts for every incoming request. | ||||
| 
 | ||||
| ### Turning on ActiveRecord database schema caching | ||||
| 
 | ||||
| If the application is using Active Record, we should turn on the schema caching | ||||
| to save the time of parsing database schema. This can be done by setting the | ||||
| `Connection::enableSchemaCache` property to be `true` via application configuration | ||||
| `protected/config/main.php`: | ||||
| 
 | ||||
| ```php | ||||
| return array( | ||||
| 	// ... | ||||
| 	'components' => array( | ||||
| 		// ... | ||||
| 		'db' => array( | ||||
| 			'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. Default is 'cache'. | ||||
| 			//'schemaCache' => 'cache', | ||||
| 		), | ||||
| 		'cache' => array( | ||||
| 			'class' => 'yii\caching\FileCache', | ||||
| 		), | ||||
| 	), | ||||
| ); | ||||
| ``` | ||||
| 
 | ||||
| Note that `cache` application component should be configured. | ||||
| 
 | ||||
| ### Combining and Minimizing Assets | ||||
| 
 | ||||
| TBD | ||||
| 
 | ||||
| ### Using better storage for sessions | ||||
| 
 | ||||
| By default PHP uses files to handle sessions. It is OK for development and | ||||
| small projects but when it comes to handling concurrent requests it's better to | ||||
| switch to another storage such as database. You can do so by configuring your | ||||
| application via `protected/config/main.php`: | ||||
| 
 | ||||
| ```php | ||||
| return array( | ||||
| 	// ... | ||||
| 	'components' => array( | ||||
| 		'session' => array( | ||||
| 			'class' => 'yii\web\DbSession', | ||||
| 
 | ||||
| 			// Set the following if want to use DB component other than | ||||
| 			// default 'db'. | ||||
| 			// 'db' => 'mydb', | ||||
| 
 | ||||
| 			// To override default session table set the following | ||||
| 			// 'sessionTable' => 'my_session', | ||||
| 		), | ||||
| 	), | ||||
| ); | ||||
| ``` | ||||
| 
 | ||||
| You can use `CacheSession` to store sessions using cache. Note that some | ||||
| cache storages such as memcached has no guaranteee that session data will not | ||||
| be lost leading to unexpected logouts. | ||||
| 
 | ||||
| Improving application | ||||
| --------------------- | ||||
| 
 | ||||
| ### Using Serverside Caching Techniques | ||||
| 
 | ||||
| As described in the Caching section, Yii provides several caching solutions that | ||||
| may improve the performance of a Web application significantly. If the generation | ||||
| of some data takes long time, we can use the data caching approach to reduce the | ||||
| data generation frequency; If a portion of page remains relatively static, we | ||||
| can use the fragment caching approach to reduce its rendering frequency; | ||||
| If a whole page remains relative static, we can use the page caching approach to | ||||
| save the rendering cost for the whole page. | ||||
| 
 | ||||
| 
 | ||||
| ### Leveraging HTTP to save procesing time and bandwidth | ||||
| 
 | ||||
| TBD | ||||
| 
 | ||||
| ### Database Optimization | ||||
| 
 | ||||
| Fetching data from database is often the main performance bottleneck in | ||||
| a Web application. Although using caching may alleviate the performance hit, | ||||
| it does not fully solve the problem. When the database contains enormous data | ||||
| and the cached data is invalid, fetching the latest data could be prohibitively | ||||
| expensive without proper database and query design. | ||||
| 
 | ||||
| Design index wisely in a database. Indexing can make SELECT queries much faster, | ||||
| but it may slow down INSERT, UPDATE or DELETE queries. | ||||
| 
 | ||||
| For complex queries, it is recommended to create a database view for it instead | ||||
| of issuing the queries inside the PHP code and asking DBMS to parse them repetitively. | ||||
| 
 | ||||
| Do not overuse Active Record. Although Active Record is good at modelling data | ||||
| in an OOP fashion, it actually degrades performance due to the fact that it needs | ||||
| to create one or several objects to represent each row of query result. For data | ||||
| intensive applications, using DAO or database APIs at lower level could be | ||||
| a better choice. | ||||
| 
 | ||||
| Last but not least, use LIMIT in your SELECT queries. This avoids fetching | ||||
| overwhelming data from database and exhausting the memory allocated to PHP. | ||||
| 
 | ||||
| ### Using asArray | ||||
| 
 | ||||
| A good way to save memory and processing time on read-only pages is to use | ||||
| ActiveRecord's `asArray` method. | ||||
| 
 | ||||
| ```php | ||||
| class PostController extends Controller | ||||
| { | ||||
| 	public function actionIndex() | ||||
| 	{ | ||||
| 		$posts = Post::find()->orderBy('id DESC')->limit(100)->asArray()->all(); | ||||
| 		echo $this->render('index', array( | ||||
| 			'posts' => $posts, | ||||
| 		)); | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| In the view you should access fields of each invidual record from `$posts` as array: | ||||
| 
 | ||||
| ```php | ||||
| foreach($posts as $post) { | ||||
| 	echo $post['title']."<br>"; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Note that you can use array notation even if `asArray` wasn't specified and you're | ||||
| working with AR objects. | ||||
| 
 | ||||
| ### Processing data in background | ||||
| 
 | ||||
| In order to respond to user requests faster you can process heavy parts of the | ||||
| request later if there's no need for immediate response. | ||||
| 
 | ||||
| - Cron jobs + console. | ||||
| - queues + handlers. | ||||
| 
 | ||||
| TBD | ||||
					Loading…
					
					
				
		Reference in new issue