What about speed? I would suppose that an indexed solution is slower, or at best no quicker, as an indirect reference is needed (from the point of the graphics card).
You are correct in that indexed rendering reads indices and then has to map them to memory addressed. This advantage however is negated many times over by vertex reuse. This involves two caches: the pre-T&L cache and the post-T&L cache.
The pre-T&L cache works more or less like a regular memory cache. If you have accessed the vertex index 1 before, and you access it again, this index will map to the same vertex attributes as before. If they’ve already been loaded into the pre-T&L cache, the only time you spend is on reading that index; there’s nothing to fetch from memory that you don’t already have.
Even more valuable is the post-T&L cache. The vertex shader guarantees that, within a single draw call, if you vertex index 1, you will get the same outputs every time. Therefore, post-vertex shader outputs are cached as well. So if you read index 1 while it is already in the post-T&L cache, not only do you save the memory access for the attributes, you don’t run the vertex shader at all.
It’s a free vertex. You can’t get that with array rendering.
With a properly ordered index list (whether in GL_TRIANGLES mode or GL_TRIANGLE_STRIP), you can theoretically make it so that each unique vertex (unique grouping of attributes) is only ever accessed once from memory.
Any rules of thumb when one technique should be used, or the other?
In general, unless you have an explicit need to do otherwise, use indexed rendering. Particles are generally when you would want to do array rendering. Those and other on-demand kinds of things (text rendering, GUI rendering etc). But if you build a mesh, particularly in an offline tool, you will want to use indexed rendering.