…or try this:
// ... put your $today and $future variables here...
global $wpdb;
$events = $wpdb->get_results(
" SELECT *
FROM {$wpdb->posts}
LEFT JOIN(
SELECT DISTINCT post_id,
(SELECT CAST(meta_value AS DATE) FROM {$wpdb->postmeta} WHERE {$wpdb->postmeta}.post_id = meta.post_id AND meta_key ='opening_time') AS opening_time,
(SELECT CAST(meta_value AS DATE) FROM {$wpdb->postmeta} WHERE {$wpdb->postmeta}.post_id = meta.post_id AND meta_key ='artist_talk_time') AS artist_talk_time,
(SELECT CAST(meta_value AS DATE) FROM {$wpdb->postmeta} WHERE {$wpdb->postmeta}.post_id = meta.post_id AND meta_key ='closing_time') AS closing_time,
(SELECT CAST(meta_value AS DATE) FROM {$wpdb->postmeta} WHERE {$wpdb->postmeta}.post_id = meta.post_id AND meta_key ='special_event_time') AS special_event_time,
FROM {$wpdb->postmeta} meta )
AS mymeta ON {$wpdb->posts}.ID = mymeta.post_id
WHERE
post_status="publish"
AND post_type="event"
AND (
mymeta.opening_time BETWEEN {$today} AND {$future}
OR mymeta.artist_talk_time BETWEEN {$today} AND {$future}
OR mymeta.closing_time BETWEEN {$today} AND {$future}
OR mymeta.special_event_time BETWEEN {$today} AND {$future}
)
GROUP BY ID
ORDER BY opening_time
LIMIT 0,10
");
var_dump($events); // you should get a list of 10 events here, ordered like you wanted
Theoretically it should be faster than what meta_query generates…