
Drupal is constantly criticized for its sluggishness, for a huge number of database queries and slowness. This is most often solved with Memcached or Varnish. In this article, I would like to add some more tips, the use of which will allow Drupal not to make it even slower. Those who are interested, please under the cat.
Together with the functionality of the site, the amount of memory consumed and the number of SQL queries required to perform a full Drupal download grows. If you need to execute just one SQL query using AJAX, Drupal can spend a lot of time to fully download and execute code that may never be used in this query. The JS module allows you to solve this problem by providing an alternative way to load Drupal only to the level necessary to perform a specific task. Including allowing you to connect the necessary files and modules to process the request.
Drupal loads itself with every request, going through a series of boot phases. All boot phases are defined in the bootstarp.inc file:
- DRUPAL_BOOTSTRAP_CONFIGURATION: This phase fills the internal array of Drupal configurations, sets the base URL, analyzes the settings.php file, etc.
- DRUPAL_BOOTSTRAP_PAGE_CACHE: Attempt to provide a page from the cache if page caching is enabled for anonymous users.
- DRUPAL_BOOTSTRAP_DATABASE: The type of database is determined and a connection is established to perform database queries.
- DRUPAL_BOOTSTRAP_VARIABLES: Initialization of a system of variables.
- DRUPAL_BOOTSTRAP_SESSION: Initialization of session processing.
- DRUPAL_BOOTSTRAP_PAGE_HEADER: Set the page title.
- DRUPAL_BOOTSTRAP_LANGUAGE: Define the page language.
- DRUPAL_BOOTSTRAP_FULL: Loading modules and initializing a theme.
For example, if you only need to use the variable_get () function in the AJAX callback, the DRUPAL_BOOTSTRAP_VARIABLES level will suffice, and if you need access to the current $ user object, you need to use DRUPAL_BOOTSTRAP_SESSION, etc.
To work with the JS module, it suffices to implement hook_js (), in which to describe which modules you need to connect, which phase of the bootstrap to use:
function js_example_js() { return array( 'results' => array( 'callback' => 'js_example_ajax_results',
It is important to understand that it is quite difficult to perform user access control in the initial stages of Drupal download, so you need to carefully monitor the security of your code.
')
Multiple entity loading
It is very often necessary to add fields from the user profile to the node and the simplest solution for this is to use the template_next template_) hook:
template_preprocess_node(&$variables) { $node = $variables['node']; $variables['account'] = user_load($node->uid); }
But when displaying a large number of nodes, this approach will create a large number of database queries. You can get the same functionality without sacrificing performance with the hook hook_entity_prepare_view ():
hook_entity_prepare_view($entities, $type, $langcode) { if ($type != 'node') { return; } $uids = array(); foreach ($entities as $entity) { $uids[] = $entity->uid; } $accounts = user_load_multiple($uids); foreach ($entities as $entity) { $entity->account = $accounts[$entity->uid]; } }
After that, the $ entity-> account will be available in the preprocess:
template_preprocess_node(&$vars) { $account = $vars['node']->account; }
Use drupal_static ()
When the code is executed several times during one request, it is very convenient to use static variables for caching. (You can read more about static variables in PHP
here and
here ). The Drupal core provides an excellent solution for implementing static caching - the drupal_static () function. The drupal_static () function provides a central static variable for storing data. The first call to drupal_static () will return NULL, but any changes to this variable will be saved for the next call to this function. Thus, we can check whether the variable has already been set and get it instantly, practically without doing any work.
function my_module_function() { $foo = &drupal_static(__FUNCTION__); global $user; if (!isset($foo[$user->uid])) { $foo[$user->uid] = something_expensive(); } return $foo[$user->uid]; }
Frequent use of variable_set () affects performance
Variables in Drupal are stored in a special table in the format: name - serialized value. With each request, all variables are loaded from the cache into the global $ conf variable.
While saving each variable, the following occurs:
- Database record updated
- Cleared cache
- When the next query finds that there is no cache for the variable table, all variables are loaded and written to the cache.
With a large number of variables, this can take a lot of time. Drupal implements a locking system and any long-running operations, in parallel with which, most likely, will receive other requests, should try to get a lock before starting work. If the previous query has cleared the cache of variables, the next query will rebuild it, so very frequent use of the variable_set () function can lead to mass table locking, due to the fact that dozens of queries are waiting for a new variable table cache entry that may become outdated before it will be removed for use.
Session table abbreviation
Drupal stores user sessions in a database, not in files, so if on sites with high traffic this table can grow to huge size very quickly. If the session table has become very large, you can increase the frequency of garbage collection for PHP sessions in settings.php:
ini_set('session.gc_maxlifetime', 86400);
I hope that not all of this list are very obvious things and it will be useful to someone.