Archive for the ‘Performance’ Category

Cache Zend_Db_Table MetaData with Zend_Cache

Thursday, February 11th, 2010

In this afternoon, my boss asked me to improving performance of project to release to client before we have Lunar new year holidays. The problem has too many DESCRIBE queries on every page load. I Google-ed & found the Lysender‘s solution, simple & easy to fix this problem:

When you are using Zend_Db_Table (I sometimes only used Zend_Db) you will notice that when you try to retrieve data from the database, the first query called is to DESCRIBE the table. Zend_Db_Table uses the information on DESCRIBE query to do its magic on SELECT.

As I have profiled my queries, I noticed that DESCRIBE query is the longest query (in most cases) which mean a big overhead over you retrieval operation. You have two options:

  1. Don’t use Zend_Db_Table (go for Zend_Db)
  2. Cache the MetaData

On this post, I’ll use the caching of MetaData. On your bootstrap file, put this piece of code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	//Caching
	$frontendOptions = array(
					'lifetime'				 => 25200,
	    				'automatic_serialization' => true
	    				);
	$backendOptions  = array(
	   					 'cache_dir'  => APPLICATION_PATH . '/tmp'
	    				);
	$cache = Zend_Cache::factory(
				'Core',
	                        'File',
	                        $frontendOptions,
	                        $backendOptions
	                    );
	//Cache table metadata
	Zend_Db_Table_Abstract::setDefaultMetadataCache($cache);

The code simply instructs Zend_Db_Table_Abstract to cache the result of DESCRIBE statement so that next time you retrieve data, the cache is used instead of repeatedly describing tables over and over again.

(But I noticed that INSERT and UPDATE statements don’t have DESCRIBE…)

After several tries with this caching, you will see files on the tmp folder like this: zend_cache—internal-metadatas—5e7576e3cd79114d46850714e998a3b0.

Still there is an overhead on reading the cache file. If you want better caching, use memory based caching like MemCache.

Source: http://lysender.co.cc/2009/03/zend-framework-optimization-tips

Optimize performance

Tuesday, September 9th, 2008

Dự án e-store tôi đang thực hiện đã sang phase II. Do đã tạo một số lượng không nhỏ các shop demo (khoảng 1500 – mặc dù yêu cầu là 5000 cái :( ) nên chức năng update toàn bộ các shop là chức năng bắt buộc phải có trong phase II này.

Ban đầu cứ nghĩ việc này khó, nhưng đến khi bắt tay vào làm mới thấy chẳng khó tý nào nếu không muốn nói là dễ :p

  1. 1 form để upload file (có validate, cấm các file execute như .sh, .exe…)
  2. File upload lên sẽ được copy vào toàn bộ các shop hiện có.
  3. Nếu file upload lên là dạng zip thì phải cho phép unzip & check như trường hợp 1

Với 3 yêu cầu này, không khó để thực hiện. Tuy vậy tôi vẫn bị vướng 1 chỗ & vẫn chưa nghĩ ra cách giải quyết nào triệt để, đó là vấn đề khi lấy toàn bộ các tên shop (shop code = thư mục) để copy file vào. Nếu trên môi trường Windows, chưa có cách nào khả thi hơn ngoài việc đọc dữ liệu trong DB. Cách này đơn giản nhưng khoảng thời gian để đọc từ DB ra cũng chẳng phải ít :( Còn trên Linux thì có vẻ dễ chịu hơn nếu như safe_mode = off :-” Tôi dùng command để đọc các thư mục shop hiện có, loại trừ đi mấy thư mục hệ thống. Hàm cụ thể như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* get all shop
* @author khanhdn
* @return array
*/
function getAllShop() {
	$shops = array('shop_temp');
 
	if(!isLinuxOS()) {
		$query = db_query("SELECT shop_code FROM {shop_setting} ORDER BY shop_code");
 
		while($rs = db_fetch_array($query)) {
			if(is_dir('../'.$rs['shop_code'])) {
				$shops[] = $rs['shop_code'];
			}
		}
	}
	else {
		$systemFolder = array(
							'system'
							,'sites'
							,'scripts'
							,'profiles'
							,'googlecheckout'
							,'themes'
							,'tmp'
							,'googleerror.log'
							,'googlemessage.log'
							,'index.php'
							,'mysqldumper'
							,'phpinfo.php'
						);
 
		$shopFolder = array();
		exec('cd ../; ls;', $shopFolder);
 
		$shops = array_diff($shopFolder, $systemFolder);
	}
 
	return $shops;
}

Thật ra thì đây chỉ là cách làm đối phó. Nếu hệ thống lớn chắc chắn vẫn không ổn. Chắc là phải làm việc ở mức thấp hơn nữa :-s