Can I only traverse a DatabaseConnection object once?
This is expected behaviour; Drupal wraps around PDO and this is how PDO query functions behave also. Have a look at Is it possible to rewind a PDO result for a more in-depth discussion.

The standard way to get around this would be to use either fetchAllKeyed() as you've mentioned, or fetchAll() instead. The latter will produce an array of object results that can be iterated over as many times as you want.

$query = db_select( ... );
$result = $query-&gt;execute();
if ( $result-&gt;rowCount() &gt; 0 ) {
  $data = $result-&gt;fetchAll();

  foreach ($data as $item) {
    // do something with data
  }

  foreach ($data as $item) {
    // do something with data again
  }
}