Index: wp-includes/query.php
===================================================================
--- wp-includes/query.php	(revision 15490)
+++ wp-includes/query.php	(working copy)
@@ -1555,15 +1555,17 @@
 
 		// First let's clear some variables
 		$distinct = '';
+		$fields = "$wpdb->posts.ID"; // see #10964
+		$quick_fields = "$wpdb->posts.*";
 		$whichcat = '';
 		$whichauthor = '';
 		$whichmimetype = '';
+		$search = '';
+		$join = '';
 		$where = '';
+		$groupby = '';
+		$orderby = '';
 		$limits = '';
-		$join = '';
-		$search = '';
-		$groupby = '';
-		$fields = "$wpdb->posts.*";
 		$post_status_join = false;
 		$page = 1;
 
@@ -2207,17 +2209,32 @@
 
 		$orderby = $q['orderby'];
 
+		// Set up quick_* defaults from the standard placeholders, before filtering
+		$quick_distinct = $distinct;
+		$quick_join = $join;
+		$quick_where = $where;
+		$quick_groupby = $groupby;
+
 		// Apply post-paging filters on where and join.  Only plugins that
 		// manipulate paging queries should use these hooks.
 		if ( !$q['suppress_filters'] ) {
-			$where = apply_filters('posts_where_paged', $where);
-			$groupby = apply_filters('posts_groupby', $groupby);
-			$join = apply_filters('posts_join_paged', $join);
+			$distinct = apply_filters('posts_distinct', $distinct, false);
+			$quick_distinct = apply_filters('posts_distinct', $quick_distinct, true);
+
+			$fields = apply_filters('posts_fields', $fields, false);
+			$quick_fields = apply_filters('posts_fields', $quick_fields, true);
+
+			$join = apply_filters('posts_join_paged', $join, false);
+			$quick_join = apply_filters('posts_join_paged', $quick_join, true);
+
+			$where = apply_filters('posts_where_paged', $where, false);
+			$quick_where = apply_filters('posts_where_paged', $quick_where, true);
+
+			$groupby = apply_filters('posts_groupby', $groupby, false);
+			$quick_groupby = apply_filters('posts_groupby', $quick_groupby, true);
+
 			$orderby = apply_filters('posts_orderby', $orderby);
-			$distinct = apply_filters('posts_distinct', $distinct);
-			$limits = apply_filters( 'post_limits', $limits );
-
-			$fields = apply_filters('posts_fields', $fields);
+			$limits = apply_filters( 'post_limits', $limits);
 		}
 
 		// Announce current selection parameters.  For use by caching plugins.
@@ -2225,28 +2242,81 @@
 
 		// Filter again for the benefit of caching plugins.  Regular plugins should use the hooks above.
 		if ( !$q['suppress_filters'] ) {
-			$where = apply_filters('posts_where_request', $where);
-			$groupby = apply_filters('posts_groupby_request', $groupby);
-			$join = apply_filters('posts_join_request', $join);
+			$distinct = apply_filters('posts_distinct_request', $distinct, false);
+			$quick_distinct = apply_filters('posts_distinct_request', $quick_distinct, true);
+
+			$fields = apply_filters('posts_fields_request', $fields, false);
+			$quick_fields = apply_filters('posts_fields_request', $quick_fields, true);
+
+			$join = apply_filters('posts_join_request', $join, false);
+			$quick_join = apply_filters('posts_join_request', $quick_join, true);
+
+			$where = apply_filters('posts_where_request', $where, false);
+			$quick_where = apply_filters('posts_where_request', $quick_where, true);
+
+			$groupby = apply_filters('posts_groupby_request', $groupby, false);
+			$quick_groupby = apply_filters('posts_groupby_request', $quick_groupby, true);
+
 			$orderby = apply_filters('posts_orderby_request', $orderby);
-			$distinct = apply_filters('posts_distinct_request', $distinct);
-			$fields = apply_filters('posts_fields_request', $fields);
-			$limits = apply_filters( 'post_limits_request', $limits );
+			$limits = apply_filters( 'post_limits_request', $limits);
 		}
 
 		if ( ! empty($groupby) )
 			$groupby = 'GROUP BY ' . $groupby;
+		if ( ! empty($quick_groupby) )
+			$quick_groupby = 'GROUP BY ' . $quick_groupby;
 		if ( !empty( $orderby ) )
 			$orderby = 'ORDER BY ' . $orderby;
 		$found_rows = '';
 		if ( !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('posts_request', $this->request);
+		if ( empty($limits) ) {
+			// do a direct query, as there is no benefit in fetching a huge load of IDs in an IN clause
+			$this->request = " SELECT $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby";
+			$this->quick_request = " SELECT $quick_distinct $quick_fields FROM $wpdb->posts $quick_join WHERE 1=1 $quick_where $quick_groupby $orderby";
 
-		$this->posts = $wpdb->get_results($this->request);
+			if ( !$q['suppress_filters'] ) {
+				$this->request = apply_filters('posts_request', $this->request, false);
+				$this->quick_request = apply_filters('posts_request', $this->quick_request, true);
+			}
+
+			$this->posts = $wpdb->get_results($this->quick_request);
+
+			$this->found_posts = count($this->posts);
+			$this->found_posts = apply_filters( 'found_posts', $this->found_posts );
+			$this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']);
+		} else {
+			$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('posts_request', $this->request);
+
+			$post_ids = $wpdb->get_col($this->request);
+
+			if ( !$post_ids ) {
+				$this->found_posts = 0;
+				$this->found_posts = apply_filters( 'found_posts', $this->found_posts );
+				$this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']);
+
+				$this->quick_request = " SELECT $quick_distinct $quick_fields FROM $wpdb->posts $quick_join WHERE 1=1 $quick_where $quick_groupby $orderby";
+				if ( !$q['suppress_filters'] )
+					$this->quick_request = apply_filters('posts_request', $this->quick_request, true);
+				$this->posts = array(); // no point in querying, since there are no posts
+			} else {
+				$found_posts_query = apply_filters( 'found_posts_query', 'SELECT FOUND_ROWS()' );
+				$this->found_posts = $wpdb->get_var( $found_posts_query );
+				$this->found_posts = apply_filters( 'found_posts', $this->found_posts );
+				$this->max_num_pages = ceil($this->found_posts / $q['posts_per_page']);
+
+				$this->quick_request = " SELECT $quick_distinct $quick_fields FROM $wpdb->posts $quick_join WHERE 1 = 1 $quick_where AND $wpdb->posts.ID IN ( " . implode(',', $post_ids) . " ) $quick_groupby ORDER BY FIELD( $wpdb->posts.ID, " . implode(',', $post_ids) . ") ";
+
+				if ( !$q['suppress_filters'] )
+					$this->quick_request = apply_filters('posts_request', $this->quick_request, true);
+
+				$this->posts = $wpdb->get_results($this->quick_request);
+			}
+		}
+
 		// Raw results filter.  Prior to status checks.
 		if ( !$q['suppress_filters'] )
 			$this->posts = apply_filters('posts_results', $this->posts);
@@ -2264,13 +2334,6 @@
 			$this->comment_count = count($this->comments);
 		}
 
-		if ( !empty($limits) ) {
-			$found_posts_query = apply_filters( 'found_posts_query', 'SELECT FOUND_ROWS()' );
-			$this->found_posts = $wpdb->get_var( $found_posts_query );
-			$this->found_posts = apply_filters( 'found_posts', $this->found_posts );
-			$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]);
