Performance is a complicated matter, especially in this case when there are several layers of technology. Sometimes it is also possible to optimize the objects that are submitted to the graphics pipeline in some high-level application-specific manner. Time permitting, it is probably best to try different implementations.
I believe that it is better to allocate the buffers once and re-use them, instead of creating new buffers every time. (As mentioned above, it may still be necessary to re-create the buffers when they are invalidated internally, but this kind of invalidation should occur rarely.) However, this strategy only describes what to do with the buffers themselves, not their contents. It is possible to fill the buffers once and not touch them for a while or to fill and flush them on every RenderScene() or even multiple times for each RenderScene(). Navisworks Core Engine mentioned above implements the latter strategy, but it is extremely optimized. (It displays graphics in a view-dependent way, so that the contents of the buffers can be expected to change despite the model being static.)
Also, as a general rule, it is better to group similar objects together. More specifically, objects that use the same EffectInstance should be submitted together or merged into one set of buffers (vertex and index). DirectContext3D allows some flexibility in following this strategy, because if the color of objects does not change, it is possible to have the color specified at each vertex and stored in the vertex buffer. One trade-off is that the size of the buffer increases when color is included.
The above comment about "how the objects in the buffers will be updated" is referring to finding the optimal strategy to group or merge buffers, if some of the objects can be modified (by a user, by a simulation, or in response to some change in the Revit model.) It is probably better for objects that can change to be kept separately.
Transformation can also be a performance factor. For example, it is possible to have many objects, each with their own transformation, or to merge them into one buffer and transform them as one unit. In other words, in a hierarchical scene, it is possible to flatten the lower level(s) of transformations by applying them to the vertices and saving the transformed vertices in the buffers. The potential benefit of doing this depends on how often the transformations need to be updated. An additional constraint in DirectContext3D is that the reported bounding box should be transformed, as well.
As for displaying thousands of identical arrows, DirectContext3D does not currently have dedicated support for instancing. So, I would consider the following optimizations, time permitting: 1) constructing the arrows in such a way that they do not need to be transformed individually and grouping them into a few large buffers (that can still be transformed with the model if needed), 2) exploring some way to cull invisible arrows (by view frustum or possibly by extracting the floors of the model and testing whether they cover some of the arrows), 3) return early from RenderScene() when DrawContext.IsInterrupted() is true (this allows drawing to be interrupted, so that Revit can respond to input events). Please, note that these potential optimizations may not result in improvement given specific scenes and constraints of a particular application.