Professional Documents
Culture Documents
The first step to tuning PHP begins with compiling an optimized version of PHP.
Avoid useless bloat and compile only the extensions you need.
Extensions that are rarely used, should be compiled as shared modules
and loaded by the few scripts requiring them.
--disable-all is your friend.
# PHP
./configure --with-apache=/path/to/apache_source
# Apache
./configure --activate-module=src/modules/php4/libphp4.a
Increased speed comes at a cost of a slightly longer installation procedure, requiring Apache recompile
every time PHP is upgraded.
Saves disk space and more importantly memory needed to load the
library or run the binary. In case of PHP makes the binary or Apache
library 20-30% smaller.
For non-persistent SAPIs like CLI prevent long searches for php.ini, by
placing the file where PHP would look for it first.
PHP CLI
/usr/local/lib/php-cli.ini
PHP CGI
/usr/local/lib/php-cgi-fcgi.ini
or
./php-cgi-fcgi.ini
Reducing File IO
● • Keep DirectoryIndex file list as short as possible.
● • Whenever possible disable .htaccess via AllowOverride none
● • Use Options FollowSymLinks to simplify file access process
in Apache
● • Avoid using mod_rewrite or at least complex regexs
● • If logs are unnecessary disable them.
● • If logging is a must, log everything to 1 file, and break it up during
analysis stage.
Lingerd is a daemon (service) designed to take over the job of properly closing network connections from an
http server like Apache.
Because of some technical complications in the way TCP/IP and HTTP work, each Apache process
currently wastes a lot of time "lingering" on client connections, after the page has been generated and sent.
Lingerd takes over this job, leaving the Apache process immediately free to handle a new connection. As a
result, Lingerd makes it possible to serve the same load using considerably fewer Apache processes.
Warning: will only work (properly) if KeepAlive is disabled.
The first step in the script execution is the conversion of said script into
a series instructions (opcodes), which the Zend Engine can understand
and run.
● • Development halted.
● • APC (PHP)
● • Slow, but steady progress.
● • Weak optimizer.
● • $$$
Often enough output of PHP scripts can remain static for an extended period of time. In these
cases, certain actions can be eliminated, resulting in a faster script execution.
Pre-generation
When the content changes, generate static versions of the affected pages, taking PHP out of the
equation completely.
On demand
Same as pre-generation, only the content is not generated until the 1st request for the specified
content arrives.
<?php
function cache_start()
{
global $cache_file_name, $age;
function cache_end()
http://talks.php.net/show/perf_tunning/20 (1 of 2) [5/29/2005 3:49:25 PM]
Performance Tuning PHP
{
global $cache_file_name;
// nothing to do
if (empty($cache_file_name)) return;
// write to cache
fwrite(fopen($cache_file_name.'_tmp', "w"), $str);
// atomic write
rename($cache_file_name.'_tmp', $cache_file_name);
}
cache_start();
<?php
require "./cache.php"; // our cache code
# Add to .htaccess
php_value auto_prepend_file "/path/to/cache.php"
As nice as PHP caching is, it is still slow, and who wants to spend time
implementing it?
Fortunately, both Zend and MMcache developers have realized this need and developed a
content caching mechanism into their PHP acceleration packages.
MMCache Content Cache
<?php
mmcache_cache_page(__FILE__, 600); // MMcache cache
<?php
// Authenticates a user and stores their id inside $uid
require "./user_auth.inc.php";
function header()
{
if ($uid) echo "Welcome {$GLOBALS['user_nick']}";
echo rest_of_header();
}
function footer()
{
if ($uid)
echo "Logout: <a href='/logout.php'>{$GLOBALS['user_nick']}</a>";
echo rest_of_footer();
}
// cache the output of the footer for 24 minutes (avg. session length)
mmcache_cache_output(__FILE__ . $uid, 'footer();', 60 * 24);
?>
Disadvantages
● • May increase CPU load by up to 10%
● • Some browsers claim to support it, but really don't.
Disadvantages
● • Can be A LOT of manual labor.
● • Older browsers (Netscape 4.0) do not support CSS.
● • Some CSS is rendered differently or is unsupported all together.
http://talks.php.net/show/perf_tunning/28 [5/29/2005 3:49:42 PM]
Performance Tuning PHP
Advantages
● • 10-30% smaller pages.
● • While compressing HTML can fix HTML bugs.
Disadvantages
● • Requires Tidy extension.
● • CPU costs make this useful only if the output is cached.
indent: no
hide-endtags: yes
char-encoding: ascii
word-2000: yes
clean: yes
bare: yes
show-errors: 0
show-warnings: no
quiet: yes
drop-proprietary-attributes: yes
hide-comments: yes
wrap: 0
<?php
ini_set("tidy.default_config", "/path/to/compact_tidy.cfg");
ini_set("tidy.clean_output", 1);
?>
Always use full path file path when opening files, to avoid expensive
normalization of the file's path.
<?php
include
"/path/to/file.php";
// or
include "./file.php";
?>
http://talks.php.net/show/perf_tunning/32 (1 of 2) [5/29/2005 3:49:49 PM]
Performance Tuning PHP
This is very important even if you use opcode cache, since the paths of
includes and normal files will still need to be resolved.
Advantages
● • Significant improvement in all File IO operations.
● • Easy to use.
Disadvantages
● • Can end up using A LOT of memory.
The surest way to accelerate sessions is by moving away from the files session handler to a
memory based one.
● • --with-mm
● • available with every PHP version.
● • not thread-safe
● • mmcache
● • very fast
Fast Query
Extra |
+----------+-------+---------------+-------+---------+------+------+------------
+
| mm_users | range | login | login | 50 | NULL | 2 | where used
|
+----------+-------+---------------+-------+---------+------+------+------------
+
Executing one query at a time is boring (and slow), chain them and
execute many queries at once.
Query Chaining
<?php
// Slow Approach
for ($i = 0; $i < 10; $i++)
mysql_query("INSERT INTO foo VALUES({$i})");
// Query Chaining
// for DBs that support it PostgreSQL, MSSQL, SQLite, MySQL 4.0+
$query = '';
for ($i = 0; $i < 10; $i++)
$query .= "INSERT INTO foo VALUES({$i});";
mysql_query($query);
http://talks.php.net/show/perf_tunning/39 (1 of 2) [5/29/2005 3:50:04 PM]
Performance Tuning PHP
?>
Performance Advantages
● • Query Cache
● • Sub-Queries (as of 4.0.4)
● • Faster bulk inserts
● • Improved FULLTEXT
<?php
// slow joinless approach
$a = sqlite_fetch_single($db, "SELECT id FROM foo WHERE name='ilia'");
$b = sqlite_array_query($db, "SELECT * FROM bar WHERE id={$a}");
Join Gotchas
● • Unoptimized joins can be VERY slow.
● • Internal (read) lock on all tables involved.
<?php
$b = sqlite_array_query($db,
"SELECT * FROM bar WHERE id=(SELECT id FROM foo WHERE name='ilia')");
?>
In MySQL, the full support for sub-queries starts from version 4.1
In many instances it is better to use Joins rather then sub-queries.
<?php
// Quickly fetch the ids of needed messages
mysql_query("CREATE TEMPORARY TABLE mtmp AS
SELECT id FROM msg WHERE
thread_id={$_GET['th']} AND apr=1
ORDER BY id ASC LIMIT {$count}, {$_GET['start']}");
AND pot.user_id="._uid."
ORDER BY m.id ASC");
?>
SQL: Right Tool for the Job Performance Tuning PHP 2005-05-29 45
PHP being is often using for templating and as such often needs to
manipulate strings, which is often done with Regular Expressions.
Common Alternatives
● • Replacement - str_replace, substr_replace, strtr, etc...
● • Matching - strpos, stripos, strchr, strrchr, etc..
● • Type Checking - ctype extension (enabled by default)
● • Comparison - strcmp, strncasecmp, etc...
● • UTF-8 support.
● • ereg
● • Always available.
<?php
$_GET['n_entries'] = (int) $_GET['n_entries'];
?>
Type conversion prevents things like SQL injection due to unexpected input. It also optimizes
the application by providing PHP with a type it expects, rather having to internally perform type
conversions each time the variable is used.
<?php
function display_function(&$obj) { ... }
$obj = mysql_fetch_object($result);
display_function($obj);
?>
<?php
function template_apply(&$str)
{
$str = str_replace(..., ..., $str);
}
?>
<?php
$foo =& $bar['foo']['bar']['test'];
$foo['imp'] = implode(',', $foo);
$foo['imp'] = addslashes($foo['imp']);
?>
Online Resources
Turck MMcache: http://sourceforge.net/projects/turck-mmcache/
APC: http://pecl.php.net/apc
Zend: http://www.zend.com
lingerd: http://www.iagora.com/about/software/lingerd/
thttpd: http://www.acme.com/software/thttpd/
Contact Me
Ilia Alshanetsky ilia@php.net