The thing to look out for is invalidating the correct caches and making sure the correct hooks are called if needed.
When updating entities directly you will need to flush the appropriate caches so the next time the entity is loaded it does not grab the old data from the cache.
entity_load()
-> DrupalDefaultEntityController::load() {uses a static cache by default}
--> DrupalDefaultEntityController::attachLoad()
---> field_attach_load() {uses the cache_field cache bin}.
Once you have that taken care of you will then need to address any 3rd party modules that use hook_entity_load() or hook_TYPE_load() (hook_node_load()). Odds are you won't have to do anything in here but it is best to double check.
Once loading has been addressed you will need to address the hooks that get ran on insert/update to make sure nothing else is done in a different place that you may not know about. hook_entity_update(), hook_entity_insert(), field_attach_presave(), hook_entity_presave(), hook_TYPE_presave() (hook_node_presave()), etc... You can follow the trail of hooks in node_save() as an example. Once again odds are nothing crazy is going to happen in here, but it is best to double check.
In regards to getting ID's entity_load_unchanged() might be what you are looking for.
Most people will tell you it is not "proper" to update fields in the database directly via SQL queries. This is because 3rd party modules might do something with that data or react to it in different ways; also be aware of modules added after you've done this workaround. In reality you can directly update the database as long as you know the risks and how the code works; most people do not and thus using the API is the best answer.
Now for the interesting part. My guess is you're looking to work around the entity api due to speed issues. There are some ways to fix this. Using a background worker to do the updates is my recommendation. register_shutdown_function() when used in combindation with HTTPRL's threading can help. I don't have a good how-to yet but here is a really quick explanation:
httprl_qcinp - Queue Callback to run In a New Process. This takes arguments similar to call_user_func_array(). I'll use a node as a example.
<?php
hook_node_save($node) {
// Preform update at the end of this request.
register_shutdown_function('my_shutdown_function', $node);
}
my_shutdown_function($node) {
// Load other entity that needs to be updated.
$alt_node = entity_load_unchanged('node', $node->some_field_reference_nid);
// Update object
$alt_node->my_field = 'updated info';
// Queue background node_save.
// node_save($alt_node);
httprl_qcinp('node_save', array($alt_node), FALSE);
// Run it.
httprl_send_request();
}
?>
At this point you might not even need HTTPRL; register_shutdown_function might do what you need.
EDIT: Also noted that this is a handy guide for just updating a single field http://timonweb.com/how-insert-and-update-only-specific-fields-your-entity-drupal-7