Not sure how dramatic this’ll be, but it should improve nontheless:
<?php
/**
* You can try forcibly splitting the query (grabbing IDs *then* all fields)
* Works well for large post results. (available WP 3.4+)
*/
add_filter( 'split_the_query', '__return_true' );
$posts = get_posts( array(
'post_type' => 'listings',
'posts_per_page' => -1,
/* Disable term caching ONLY if you're not using them in your loop. */
'update_post_term_cache' => false,
/* Ensures SQL_CALC_FOUND_ROWS is disabled */
'no_found_rows' => true,
/* If you're only operating on these, filter out at the query stage rather than the loop. */
'meta_key' => 'mymeta',
));
header( 'Content-Type: application/rss+xml; charset=UTF-8' );
echo '<?xml version="1.0"?>';
?>
<rss version="2.0">
<channel>
<title>My custom feed</title>
<?php foreach ( $posts as $post ) : ?>
<item>
<various item elements...>
</item>
<?php endforeach ?>
</channel>
</rss>