A fast way to access an object is using its object ID. This kind of retrieval is only possible for well-known objects that your application expects to find, such as a container (that is, folder or package) object that is the root of a container hierarchy.
If a given set of objects is usually loaded together, it is helpful to have a relationship collection that points to those objects. If you access the objects through that collection, the engine will load them in one round-trip.
Think twice before navigating to a collection which contains only one or two objects of interest. You'll be paying to load the entire collection. Instead try to find another way to navigate to those objects.
When you know the exact set of objects you want, IRepositoryODBC::ExecuteQuery is often a faster way to find the objects than navigating to them via collections, since it usually requires many fewer round-trips. For convenience, consider writing some view definitions to insulate application programmers from the complexity of the relationship table (RTblRelationships) and type definitions (for example, RTblClassDefs, RTblIfaceDefs). If the query-update ratio warrants it, consider adding indexes to the Repository's interface tables (the ones to which that interfaces' properties are mapped.
ExecuteQuery can be run asynchronously, in which case the call returns immediately. Later, you use IObjectCol2 to determine whether the collection that is being loaded is ready to read.
You can use ExecuteQuery to explicitly tell the Microsoft® Repository engine to pre-fetch certain objects. However, in addition to calling ExecuteQuery, for at least one object in the ObjectCollection that the query returns, you must access a property on each interface you want to access. This tells the engine to pre-fetch the properties on those interfaces for all the objects in the collection's contents. As an aside, the engine flushes all updates to the database before running ExecuteQuery, so the query is reading exactly the current database state.
If an object has the same name in all contexts, make sure its class supports INamedObject. This makes it more efficient to fetch the name. That is, the engine fetches the name from INamedObject::Name, instead of from any of the incoming relationships. Note that an update of the name causes an update to all naming relationships pointing to the name.
If an object supports INamedObject, then the most efficient way to set the Name property on the object only (and not on any of its incoming relationships) is to explicitly QueryInterface for INamedObject and set its Name property. For example:
Dim oReposObj as RepositoryObject
Set oReposObj.Interface("INamedObject").Name = "Any Name"
Note that since the names of the relationships to the object are not updated here, you cannot later fetch by name from the collection. Rather, you have to enumerate the collection and check each object's name. Also note that the property Name corresponds to the dispatch ID DISPID_ObjName (not DISPID_Name).
It is more efficient to follow a relationship in the origin-to-destination direction than vice versa. This is because the physical representation of relationships in the relationship table is biased in this direction. So, traverse relationships in this direction whenever you have a choice.