Index: src/wp-includes/class-wp-site-query.php
===================================================================
--- src/wp-includes/class-wp-site-query.php	(revision 42373)
+++ src/wp-includes/class-wp-site-query.php	(working copy)
@@ -240,16 +240,7 @@
 		 */
 		do_action_ref_array( 'pre_get_sites', array( &$this ) );
 
-		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
-		$_args = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) );
-
-		// Ignore the $fields argument as the queried result will be the same regardless.
-		unset( $_args['fields'] );
-
-		$key          = md5( serialize( $_args ) );
-		$last_changed = wp_cache_get_last_changed( 'sites' );
-
-		$cache_key   = "get_sites:$key:$last_changed";
+		$cache_key   = $this->get_cache_key( $this->query_vars );
 		$cache_value = wp_cache_get( $cache_key, 'sites' );
 
 		if ( false === $cache_value ) {
@@ -698,4 +689,74 @@
 			return 'DESC';
 		}
 	}
+
+	/**
+	 * Generates the cache key to lookup query results for a specific set of arguments.
+	 *
+	 * @since 5.0.0
+	 *
+	 * @param array $query_vars Array of WP_Site_Query arguments. See WP_Site_Query::__construct().
+	 * @return string Cache key to use for the lookup.
+	 */
+	protected function get_cache_key( $query_vars ) {
+		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
+		$_args = wp_array_slice_assoc( $query_vars, array_keys( $this->query_var_defaults ) );
+
+		// Ignore the $fields argument as the queried result will be the same regardless.
+		unset( $_args['fields'] );
+
+		// Ignore the $update_site_cache as it does not affect the query.
+		unset( $_args['update_site_cache'] );
+
+		// Use the same cache key for array lookups with one element and single value lookups.
+		$single_multi_mappings = array(
+			'ID'         => 'site__in',
+			'network_id' => 'network__in',
+			'domain'     => 'domain__in',
+			'path'       => 'path__in',
+			'lang_id'    => 'lang__in',
+		);
+		foreach ( $single_multi_mappings as $single_var => $multi_var ) {
+			if ( empty( $_args[ $single_var ] ) && isset( $_args[ $multi_var ] ) && is_array( $_args[ $multi_var ] ) && count( $_args[ $multi_var ] ) === 1 ) {
+				$_args[ $single_var ] = array_pop( $_args[ $multi_var ] );
+				$_args[ $multi_var ] = '';
+			}
+		}
+
+		$key = md5( serialize( $_args ) );
+
+		/* The following part of the code checks some common combinations of query vars.
+		 * If all non-empty values that actually affect the last_changed date for the query
+		 * belong to one of the special argument combinations, a more specific last_changed
+		 * cache key is used instead of the global one. */
+
+		// Only consider arguments that are not empty and have thus been passed to the query.
+		$used_args = array_filter( $_args );
+
+		// The following arguments affect the query result, but not its last_changed value.
+		$ignore_args = array( 'number', 'offset', 'no_found_rows', 'orderby', 'order', 'count' );
+		$used_args   = array_diff_key( $used_args, array_flip( $ignore_args ) );
+
+		// The following arguments are relevant for a special 'last_changed' prefix.
+		$last_changed_keys = array( 'domain', 'path', 'network_id' );
+
+		$last_changed_args = array();
+		foreach ( $last_changed_keys as $key ) {
+			if ( isset( $used_args[ $key ] ) ) {
+				$last_changed_args[ $key ] = (string) $used_args[ $key ];
+				unset( $used_args[ $key ] );
+			}
+		}
+
+		// Only use a special 'last_changed' prefix if no other arguments are present.
+		if ( ! empty( $last_changed_args ) && empty( $used_args ) ) {
+			$last_changed_prefix = md5( serialize( $last_changed_args ) ) . '_';
+		} else {
+			$last_changed_prefix = '';
+		}
+
+		$last_changed = wp_cache_get_last_changed( 'sites', $last_changed_prefix );
+
+		return "get_sites:$key:$last_changed";
+	}
 }
Index: src/wp-includes/functions.php
===================================================================
--- src/wp-includes/functions.php	(revision 42373)
+++ src/wp-includes/functions.php	(working copy)
@@ -5952,17 +5952,21 @@
  * Get last changed date for the specified cache group.
  *
  * @since 4.7.0
+ * @since 5.0.0 Now supports the $prefix parameter.
  *
- * @param string $group Where the cache contents are grouped.
+ * @param string $group  Where the cache contents are grouped.
+ * @param string $prefix Optional. Prefix to look for a specific last changed key. Default empty string.
  *
  * @return string $last_changed UNIX timestamp with microseconds representing when the group was last changed.
  */
-function wp_cache_get_last_changed( $group ) {
-	$last_changed = wp_cache_get( 'last_changed', $group );
+function wp_cache_get_last_changed( $group, $prefix = '' ) {
+	$key = $prefix . 'last_changed';
+
+	$last_changed = wp_cache_get( $key, $group );
 
 	if ( ! $last_changed ) {
 		$last_changed = microtime();
-		wp_cache_set( 'last_changed', $last_changed, $group );
+		wp_cache_set( $key, $last_changed, $group );
 	}
 
 	return $last_changed;
Index: src/wp-includes/ms-blogs.php
===================================================================
--- src/wp-includes/ms-blogs.php	(revision 42373)
+++ src/wp-includes/ms-blogs.php	(working copy)
@@ -459,6 +459,7 @@
 				'blog_id' => $blog_id,
 				'domain'  => null,
 				'path'    => null,
+				'site_id' => get_current_network_id(),
 			)
 		);
 	}
@@ -486,7 +487,33 @@
 	 */
 	do_action( 'clean_site_cache', $blog_id, $blog, $domain_path_key );
 
-	wp_cache_set( 'last_changed', microtime(), 'sites' );
+	$current_time = microtime();
+
+	// The following arguments are relevant for a special 'last_changed' prefix.
+	$last_changed_args = array(
+		'domain'     => $blog->domain,
+		'path'       => $blog->path,
+		'network_id' => $blog->site_id,
+	);
+
+	$last_changed_prefixes = array( '' );
+
+	// Generate all possible variations.
+	$combinations = array( array() );
+	foreach ( $last_changed_args as $key => $value ) {
+		$value = (string) $value;
+
+		foreach ( $combinations as $combination ) {
+			$current_args = array_merge( $combination, array( $key => $value ) );
+			$last_changed_prefixes[] = md5( serialize( $current_args ) ) . '_';
+
+			$combinations[] = $current_args;
+		}
+	}
+
+	foreach ( $last_changed_prefixes as $last_changed_prefix ) {
+		wp_cache_set( $last_changed_prefix . 'last_changed', $current_time, 'sites' );
+	}
 
 	/**
 	 * Fires after the blog details cache is cleared.
