Before: Executed 595 queries in 207 milliseconds.
After: Executed 158 queries in 95.37 milliseconds.
I changed drupal_lookup_path() to accept $path as an array of paths and use src in(....). I changed menu_tree_check_access to call drupal_lookup_path('alias', $paths). menu has a big list of node ids that are selected from the database in one hit. Later, when drupal_lookup_path() is asked to find an alias, the request is answered from the cache. Stats provided by devel module.

The change to menu preloads only the primary menu, which is the biggest on my sites. menu.inc could also preload the admin menu. I have note found out where that is done. The change to menu preloads node aliases but not taxonomy aliases.

The example changes below do not check if aliasing is used or useful.

Here is the changed alias part of drupal_lookup_path(). It does not use a proper placeholder setup.

  elseif ($count > 0 && ((is_array($path) and count($path) > 0) or $path != '')) {
    if ($action == 'alias') {
	   if(is_array($path))
		   {
		$paths = array();
		   foreach($path as $path_entry)
			{
			if (isset($map[$path_language][$path_entry]))
				{
				$paths[] = $map[$path_language][$path_entry];
				unset($path[$path_entry]);
				}
			}
		if (count($path) == 0)
			{
			return $paths;
			}
	   }
	   else
	   {
      if (isset($map[$path_language][$path])) {
        return $map[$path_language][$path];
      }
      }

Here is the changed menu_tree_check_access().

function menu_tree_check_access(&$tree, $node_links = array()) {
  if ($node_links) {
	  $paths = array();
    // Use db_rewrite_sql to evaluate view access without loading each full node.
    $nids = array_keys($node_links);
    $placeholders = '%d'. str_repeat(', %d', count($nids) - 1);
    $result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.status = 1 AND n.nid IN (". $placeholders .")"), $nids);
    while ($node = db_fetch_array($result)) {
      $nid = $node['nid'];
      foreach ($node_links[$nid] as $mlid => $link) {
        $node_links[$nid][$mlid]['access'] = TRUE;
	$paths[] = 'node/' . $nid;
      }
    }
    drupal_lookup_path('alias', $paths);
  }
  _menu_tree_check_access($tree);
  return;
}

Comments

peterx’s picture

I left a code change out of the last entry:

      // Get the most fitting result falling back with alias without language
	   if(is_array($path))
		 {
      $result = db_query("SELECT dst, src FROM {url_alias} WHERE src in('" . implode("','", $path) . "') AND language IN('%s', '') ORDER BY language DESC", $path_language);
      while($alias = db_fetch_array($result))
	      {
//	      $map[$path_language][$alias['src']] = $alias['dst'];
	      $paths[$alias['src']] = $alias['dst'];
	      }
      return $paths;
		 }
		 else

If we return the array of aliases then we do not have to cache them because menu can pass the alias internally.

Checking where drupal_lookup_path is used. Trace back:
drupal_lookup_path(includes/path.inc, 156)
drupal_get_path_alias(includes/common.inc, 1475)
url(includes/common.inc, 1601)
l(sites/all/themes/christmas/template.php, 311)
christmas_menu_item_link(, )
call_user_func_array(includes/theme.inc, 617)
theme(includes/menu.inc, 758)
menu_tree_output(includes/menu.inc, 760)
menu_tree_output(includes/menu.inc, 724)
menu_tree(sites/all/themes/christmas/page.tpl.php, 112)
include(includes/theme.inc, 1020)
theme_render_template(includes/theme.inc, 686)
theme(index.php, 36)

I will suggest a change for menu in http://drupal.org/node/625968

Dave Reid’s picture

Status: Active » Closed (duplicate)

See #106559: drupal_lookup_path() optimization - skip looking up certain paths in drupal_lookup_path() will help a lot with this. 6.x is also closed to feature requests.