Index: wp-includes/default-filters.php
===================================================================
--- wp-includes/default-filters.php	(revision 33517)
+++ wp-includes/default-filters.php	(working copy)
@@ -387,6 +387,9 @@
 // Media
 add_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );
 add_action( 'customize_controls_enqueue_scripts', 'wp_plupload_default_settings' );
+add_action( 'add_attachment', 'wp_check_has_media' );
+add_action( 'delete_attachment', 'wp_check_has_media' );
+add_action( 'add_attachment', 'wp_check_media_months' );
 
 // Nav menu
 add_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once', 10, 2 );
Index: wp-includes/media.php
===================================================================
--- wp-includes/media.php	(revision 33517)
+++ wp-includes/media.php	(working copy)
@@ -2944,26 +2944,10 @@
 		}
 	}
 
-	$has_audio = $wpdb->get_var( "
-		SELECT ID
-		FROM $wpdb->posts
-		WHERE post_type = 'attachment'
-		AND post_mime_type LIKE 'audio%'
-		LIMIT 1
-	" );
-	$has_video = $wpdb->get_var( "
-		SELECT ID
-		FROM $wpdb->posts
-		WHERE post_type = 'attachment'
-		AND post_mime_type LIKE 'video%'
-		LIMIT 1
-	" );
-	$months = $wpdb->get_results( $wpdb->prepare( "
-		SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
-		FROM $wpdb->posts
-		WHERE post_type = %s
-		ORDER BY post_date DESC
-	", 'attachment' ) );
+	$has_audio = media_has_audio();
+	$has_video = media_has_video();
+	$months = media_months();
+
 	foreach ( $months as $month_year ) {
 		$month_year->text = sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month_year->month ), $month_year->year );
 	}
@@ -2982,8 +2966,8 @@
 		),
 		'defaultProps' => $props,
 		'attachmentCounts' => array(
-			'audio' => ( $has_audio ) ? 1 : 0,
-			'video' => ( $has_video ) ? 1 : 0
+			'audio' => intval( $has_audio ),
+			'video' => intval( $has_video )
 		),
 		'embedExts'    => $exts,
 		'embedMimes'   => $ext_mimes,
@@ -3470,3 +3454,152 @@
 
 	return array( $mediaelement, $wpmediaelement );
 }
+
+/**
+ * Check if there are any audio items in the media library.
+ *
+ * Queries the DB to check whether the media library contains any items of type audio,
+ * and caches that expensive query to avoid slowness when saving posts on large sites.
+ *
+ * @return int Returns 1 or 0 for 'yes' or 'no'
+ */
+function media_has_audio() {
+
+	$has_audio = get_transient( 'has_audio' );
+	if ( false === $has_audio ) {
+		global $wpdb;
+		$has_audio = $wpdb->get_var( "
+			SELECT ID
+			FROM $wpdb->posts
+			WHERE post_type = 'attachment'
+			AND post_mime_type LIKE 'audio%'
+			LIMIT 1
+		" );
+		$has_audio = $has_audio ? 1 : 0;
+		set_transient( 'has_audio', $has_audio );
+	}
+
+	return $has_audio;
+
+}
+
+/**
+ * Check if there are any video items in the media library.
+ *
+ * Queries the DB to check whether the media library contains any items of type video,
+ * and caches that expensive query to avoid slowness when saving posts on large sites.
+ *
+ * @return int Returns 1 or 0 for 'yes' or 'no'
+ */
+function media_has_video() {
+
+	$has_video = get_transient( 'has_video' );
+	if ( false === $has_video ) {
+		global $wpdb;
+		$has_video = $wpdb->get_var( "
+			SELECT ID
+			FROM $wpdb->posts
+			WHERE post_type = 'attachment'
+			AND post_mime_type LIKE 'video%'
+			LIMIT 1
+		" );
+		$has_video = $has_video ? 1 : 0;
+		set_transient( 'has_video', $has_video );
+	}
+
+	return $has_video;
+}
+
+/**
+ * Gets a list of months in which media has been uploaded
+ *
+ * Queries the DB to check in which months media items have been uploaded, then
+ * caches that query which can be expensive on larger sites
+ *
+ * @return array An array of objects representing rows from the DB query
+ */
+function media_months() {
+
+	$months = get_transient( 'media_months' );
+	if ( false === $months ) {
+		global $wpdb;
+		$months = $wpdb->get_results( $wpdb->prepare( "
+			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
+			FROM $wpdb->posts
+			WHERE post_type = %s
+			ORDER BY post_date DESC
+		", 'attachment' ) );
+		set_transient( 'media_months', $months );
+	}
+
+	return $months;
+
+}
+
+/**
+ * Updates the has_audio and has_video transients as required
+ *
+ * Hooks into `add_attachment` and `delete_attachment` to determine whether or not
+ * the has_audio and has_video transients needs to be refreshed.
+ *
+ * @param $post_id ID of the attachment post added/deleted
+ */
+function wp_check_has_media( $post_id ) {
+
+	$mime_type = get_post_mime_type( $post_id );
+
+	$post_status = get_post_status( $post_id );
+
+	// The value of the transient we should clear, where relevant.
+	$transient_to_clear = null;
+
+	if ( 'trash' == $post_status ) {
+
+		// We're deleting an attachment so we should only refresh the transient
+		// if it indicates there are attachments of this type
+		$transient_to_clear = 1;
+
+	} else {
+
+		// We're adding an attachment so we should only refresh the transient
+		// if it indicates there are currently no attachments of this type
+		$transient_to_clear = 0;
+
+	}
+
+	// Based on attachment type, clear the relevant transient where necessary
+	if ( 'image' == $mime_type && $transient_to_clear == media_has_audio() ){
+		delete_transient( 'has_audio' );
+	} else if ( 'video' == $mime_type && $transient_to_clear === media_has_video() ) {
+		delete_transient( 'has_video' );
+	}
+
+
+}
+
+function wp_check_media_months( $post_id ) {
+
+	// What month/year is the most recent attachment?
+	global $wpdb;
+	$months = $wpdb->get_results( $wpdb->prepare( "
+			SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
+			FROM $wpdb->posts
+			WHERE post_type = %s
+			ORDER BY post_date DESC
+			LIMIT 1
+		", 'attachment' ) );
+
+	// Simplify by assigning the object to $months
+	$months = array_shift( array_values( $months ) );
+
+	// Compare the dates of the new, and most recent, attachment
+	if (
+		! $months->year == get_the_time( 'Y', $post_id ) &&
+		! $months->month == get_the_time( 'm', $post_id )
+	) {
+		// the new attachment is not in the same month/year as the
+		// most recent attachment, so we need to refresh the transient
+		delete_transient('media_months');
+	}
+
+}
\ No newline at end of file
