Index: wp-admin/includes/template.php
===================================================================
--- wp-admin/includes/template.php	(revision 13173)
+++ wp-admin/includes/template.php	(working copy)
@@ -1789,16 +1789,17 @@
 }
 
 /**
- * {@internal Missing Short Description}}
+ * Generate HTML for a single row on the users.php admin panel.
  *
  * @since unknown
  *
- * @param unknown_type $user_object
- * @param unknown_type $style
- * @param unknown_type $role
- * @return unknown
+ * @param object $user_object
+ * @param string $style Optional. Attributes added to the TR element.  Must be sanitized.
+ * @param string $role Key for the $wp_roles array.
+ * @param int $numposts Optional. Post count to display for this user.  Defaults to zero, as in, a new user has made zero posts.
+ * @return string
  */
-function user_row( $user_object, $style = '', $role = '' ) {
+function user_row( $user_object, $style = '', $role = '', $numposts = 0 ) {
 	global $wp_roles;
 
 	$current_user = wp_get_current_user();
@@ -1814,7 +1815,6 @@
 		$short_url = substr( $short_url, 0, -1 );
 	if ( strlen( $short_url ) > 35 )
 		$short_url = substr( $short_url, 0, 32 ).'...';
-	$numposts = get_usernumposts( $user_object->ID );
 	$checkbox = '';
 	// Check if the user for this row is editable
 	if ( current_user_can( 'edit_user', $user_object->ID ) ) {
Index: wp-admin/users.php
===================================================================
--- wp-admin/users.php	(revision 13173)
+++ wp-admin/users.php	(working copy)
@@ -208,9 +208,12 @@
 	$userspage = isset($_GET['userspage']) ? $_GET['userspage'] : null;
 	$role = isset($_GET['role']) ? $_GET['role'] : null;
 
-	// Query the users
+	// Query the user IDs for this page
 	$wp_user_search = new WP_User_Search($usersearch, $userspage, $role);
 
+	// Query the post counts for this page
+	$post_counts = get_users_numposts($wp_user_search->get_results());
+
 	$messages = array();
 	if ( isset($_GET['update']) ) :
 		switch($_GET['update']) {
@@ -265,16 +268,10 @@
 <?php
 $role_links = array();
 $avail_roles = array();
-$users_of_blog = get_users_of_blog();
-$total_users = count( $users_of_blog );
-foreach ( (array) $users_of_blog as $b_user ) {
-	$b_roles = unserialize($b_user->meta_value);
-	foreach ( (array) $b_roles as $b_role => $val ) {
-		if ( !isset($avail_roles[$b_role]) )
-			$avail_roles[$b_role] = 0;
-		$avail_roles[$b_role]++;
-	}
-}
+
+$users_of_blog = count_blog_users_by_role_intime();
+$total_users = $users_of_blog['total_users'];
+$avail_roles =& $users_of_blog['avail_roles'];
 unset($users_of_blog);
 
 $current_role = false;
@@ -372,7 +369,7 @@
 	$role = array_shift($roles);
 
 	$style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
-	echo "\n\t" . user_row($user_object, $style, $role);
+	echo "\n\t", user_row($user_object, $style, $role, $post_counts[(string)$userid]);
 }
 ?>
 </tbody>
Index: wp-includes/user.php
===================================================================
--- wp-includes/user.php	(revision 13173)
+++ wp-includes/user.php	(working copy)
@@ -179,11 +179,42 @@
 function get_usernumposts($userid) {
 	global $wpdb;
 	$userid = (int) $userid;
-	$count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts WHERE post_author = %d AND post_type = 'post' AND ", $userid) . get_private_posts_cap_sql('post'));
+	$count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->posts WHERE post_author = %d AND post_type = 'post' AND post_status IN ('publish', 'private')", $userid) );
 	return apply_filters('get_usernumposts', $count, $userid);
 }
 
 /**
+ * Number of posts written by a list of users.
+ *
+ * @since 3.0.0
+ * @param array $userid User ID number list.
+ * @return array Amount of posts each user has written.
+ */
+function get_users_numposts($users) {
+	global $wpdb;
+	
+	if (0 == count($users))
+		return array();
+	    
+	$userlist = implode(',', $users);
+	
+	$result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts WHERE post_author IN ($userlist) AND post_type = 'post' AND post_status IN ('publish', 'private') GROUP BY post_author", ARRAY_N );
+
+	$count = array();
+	foreach($result as $row) {
+		$count[$row[0]] = $row[1];
+	}
+
+	foreach($users as $id) {
+		$id = (string) $id;
+		if (!isset($count[$id]))
+			$count[$id] = 0;
+	}
+
+	return $count;
+}
+
+/**
  * Check that the user login name and password is correct.
  *
  * @since 0.71
@@ -440,6 +471,93 @@
 	return true;
 }
 
+/**
+ * Count number of users who have each of the user roles.
+ *
+ * Assumes there are neither duplicated nor orphaned capabilities meta_values.
+ * Assumes the serialized array values are meaningless, only array keys are used.
+ * Intended scale for this version is 10^5 users.  It is not quite capable of that yet due to WP Bug #12257
+ * Memory exhaustion is expected at higher orders.
+ *
+ * @since 3.0.0
+ * @return array Includes a grand total and an array of counts indexed by role strings.
+ */
+function count_blog_users_by_role_inmem() {
+	global $wpdb, $blog_id;
+
+	$id = (int) $blog_id;
+	$blog_prefix = $wpdb->get_blog_prefix($id);
+	$avail_roles = array();
+
+	$users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
+
+	foreach ( $users_of_blog as $caps_meta ) {
+		$b_roles = unserialize($caps_meta);
+		if ( is_array($b_roles) ) {
+			foreach ( $b_roles as $b_role => $val ) {
+				if ( isset($avail_roles[$b_role]) )
+					$avail_roles[$b_role]++;
+				else
+					$avail_roles[$b_role] = 1;
+			}
+		}
+	}
+
+	$result = array();
+	$result['total_users'] = count( $users_of_blog );
+	$result['avail_roles'] =& $avail_roles;
+	
+	return $result;
+}
+
+/**
+ * Count number of users who have each of the user roles.
+ *
+ * Assumes there are neither duplicated nor orphaned capabilities meta_values.
+ * Assumes role names are unique phrases.  Same assumption made by WP_User_Search::prepare_query()
+ * Intended scale for this version is 10^7 users.
+ * CPU exhaustion is expected at higher orders.
+ *
+ * @since 3.0.0
+ * @return array Includes a grand total and an array of counts indexed by role strings.
+ */
+function count_blog_users_by_role_intime() {
+	global $wpdb, $blog_id, $wp_roles;
+
+	// Initialize
+	$id = (int) $blog_id;
+	$blog_prefix = $wpdb->get_blog_prefix($id);
+	$avail_roles = $wp_roles->get_names();
+
+	// Build a CPU-intensive query that will return concise information.
+	$select_count = array();
+	foreach ( $avail_roles as $this_role => $name ) {
+		$select_count[] = "COUNT(NULLIF(`meta_value` LIKE '%" . like_escape($this_role) . "%', FALSE))";
+	}
+	$select_count = implode(', ', $select_count);
+
+	// Add the meta_value index to the selection list, then run the query.
+	$row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
+
+	// Run the previous loop again to associate results with role names.
+	$col = 0;
+	$role_counts = array();
+	foreach ( $avail_roles as $this_role => $name ) {
+		$count = (int) $row[$col++];
+		if ($count > 0)
+			$role_counts[$this_role] = $count;
+	}
+
+	// Get the meta_value index from the end of the result set.
+	$total_users = (int) $row[$col];
+
+	$result = array();
+	$result['total_users'] = $total_users;
+	$result['avail_roles'] =& $role_counts;
+
+	return $result;
+}
+
 //
 // Private helper functions
 //
