From 6aedd9d0f0f76effaa10f794a495d12755c7d57b Mon Sep 17 00:00:00 2001 From: ryan Date: Tue, 14 Feb 2012 15:09:35 +0000 Subject: [PATCH] Split the main WP_Query posts query into two queries to avoid temp tables. Leverage cache to avoid second query in persistent cache environments. Props scribu, cheald, prettyboymp. see #18536 git-svn-id: http://svn.automattic.com/wordpress/trunk@19918 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/functions.php | 23 +++++++++++ wp-includes/pluggable.php | 8 +--- wp-includes/post-thumbnail-template.php | 8 +--- wp-includes/post.php | 23 +++++++++++ wp-includes/query.php | 51 +++++++++++++++++++------ 5 files changed, 88 insertions(+), 25 deletions(-) diff --git a/wp-includes/functions.php b/wp-includes/functions.php index 50df62131b..a5975f12fd 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -3703,3 +3703,26 @@ function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pr else return $caller; } + +/** + * Retrieve ids that are not already present in the cache + * + * @since 3.4.0 + * + * @param array $object_ids ID list + * @param string $cache_key The cache bucket to check against + * + * @return array + */ +function _get_non_cached_ids( $object_ids, $cache_key ) { + $clean = array(); + foreach ( $object_ids as $id ) { + $id = (int) $id; + if ( !wp_cache_get( $id, $cache_key ) ) { + $clean[] = $id; + } + } + + return $clean; +} + diff --git a/wp-includes/pluggable.php b/wp-includes/pluggable.php index a6b7b47ea7..08623f5e82 100644 --- a/wp-includes/pluggable.php +++ b/wp-includes/pluggable.php @@ -139,13 +139,7 @@ if ( !function_exists('cache_users') ) : function cache_users( $user_ids ) { global $wpdb; - $clean = array(); - foreach ( $user_ids as $id ) { - $id = (int) $id; - if ( !wp_cache_get( $id, 'users' ) ) { - $clean[] = $id; - } - } + $clean = _get_non_cached_ids( $user_ids, 'users' ); if ( empty( $clean ) ) return; diff --git a/wp-includes/post-thumbnail-template.php b/wp-includes/post-thumbnail-template.php index b4cf8bfe54..ab8941f701 100644 --- a/wp-includes/post-thumbnail-template.php +++ b/wp-includes/post-thumbnail-template.php @@ -64,13 +64,7 @@ function update_post_thumbnail_cache() { } if ( ! empty ( $thumb_ids ) ) { - get_posts( array( - 'update_post_term_cache' => false, - 'include' => $thumb_ids, - 'post_type' => 'attachment', - 'post_status' => 'inherit', - 'nopaging' => true - ) ); + _prime_post_caches( $thumb_ids, false, true ); } $wp_query->thumbnails_cached = true; diff --git a/wp-includes/post.php b/wp-includes/post.php index e6713ac983..ae35922b77 100644 --- a/wp-includes/post.php +++ b/wp-includes/post.php @@ -5318,3 +5318,26 @@ function _update_term_count_on_transition_post_status( $new_status, $old_status, wp_update_term_count( $tt_ids, $taxonomy ); } } + +/** + * Adds any posts from the given ids to the cache that do not already exist in cache + * + * @since 3.4.0 + * + * @access private + * + * @param array $post_ids ID list + * @param bool $update_term_cache Whether to update the term cache. Default is true. + * @param bool $update_meta_cache Whether to update the meta cache. Default is true. + */ +function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) { + global $wpdb; + + $non_cached_ids = _get_non_cached_ids( $ids, 'posts' ); + if ( !empty( $non_cached_ids ) ) { + $fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", join( ",", $non_cached_ids ) ) ); + + update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache ); + } +} + diff --git a/wp-includes/query.php b/wp-includes/query.php index 8741d6f9df..e5b3ee498a 100644 --- a/wp-includes/query.php +++ b/wp-includes/query.php @@ -2606,9 +2606,11 @@ class WP_Query { if ( !$q['no_found_rows'] && !empty($limits) ) $found_rows = 'SQL_CALC_FOUND_ROWS'; - $this->request = " SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits"; - if ( !$q['suppress_filters'] ) - $this->request = apply_filters_ref_array('posts_request', array( $this->request, &$this ) ); + $this->request = $old_request = "SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits"; + + if ( !$q['suppress_filters'] ) { + $this->request = apply_filters( 'posts_request', $this->request, $this ); + } if ( 'ids' == $q['fields'] ) { $this->posts = $wpdb->get_col($this->request); @@ -2626,7 +2628,29 @@ class WP_Query { return $r; } - $this->posts = $wpdb->get_results($this->request); + if ( $old_request == $this->request && "$wpdb->posts.*" == $fields ) { + // First get the IDs and then fill in the objects + + $this->request = "SELECT $found_rows $distinct $wpdb->posts.ID FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits"; + + $this->request = apply_filters( 'posts_request_ids', $this->request, $this ); + + $ids = $wpdb->get_col( $this->request ); + + if ( $ids ) { + $this->set_found_posts( $q, $limits ); + + _prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] ); + + $this->posts = array_map( 'get_post', $ids ); + } else { + $this->found_posts = $this->max_num_pages = 0; + $this->posts = array(); + } + } else { + $this->posts = $wpdb->get_results( $this->request ); + $this->set_found_posts( $q, $limits ); + } // Raw results filter. Prior to status checks. if ( !$q['suppress_filters'] ) @@ -2645,13 +2669,6 @@ class WP_Query { $this->comment_count = count($this->comments); } - if ( !$q['no_found_rows'] && !empty($limits) ) { - $found_posts_query = apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ); - $this->found_posts = $wpdb->get_var( $found_posts_query ); - $this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) ); - $this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']); - } - // Check post status to determine if post should be displayed. if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) { $status = get_post_status($this->posts[0]); @@ -2754,6 +2771,18 @@ class WP_Query { return $this->posts; } + function set_found_posts( $q, $limits ) { + global $wpdb; + + if ( $q['no_found_rows'] || empty( $limits ) ) + return; + + $this->found_posts = $wpdb->get_var( apply_filters( 'found_posts_query', 'SELECT FOUND_ROWS()', $this ) ); + $this->found_posts = apply_filters( 'found_posts', $this->found_posts, $this ); + + $this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] ); + } + /** * Set up the next post and iterate current post index. *