Does row versioning increase the size of indexes? Row versioning maintains 14 bytes of internal versioning information for each row. But is this really a cost per row or is this a cost that also applies to each index on the table?

It seems the 14 bytes must be added to all index records as well so that index-only scans (and other index-only accesses) can see the versioning information and perceive a point in time snapshot of the data.

All information that I could find on the web only talks about a per row overhead of 14 bytes, though.
It seems the 14 bytes must be added to all index records as well


Why should it be added to all index records? Do you mean all indexes, or all rows of all indexes?

Only the affected rows of the affected indexes will get 14 bytes tag.

Here are 3 examples.

Suppose we have clustered table of 100 pages (with id int PK) and 1 nonclustered index on it (on another column Col1), and we change 10 keys (id) of clustered index. 

All 10 rows of clustered table will get row version tag (10 rows, not 100 rows), and the 10 affected rows of nonclustered index will have this tag because every nonclustered index contains clustered index key at least at the leaf level, so 10 rows of nonclustered index will have their versions too.

You can prove it to yourself by changing 10 rows in clustered table having nonclustered index in db with RCSI and by checking sys.dm_tran_version_store: there will be 20 rows and you'll be able to distinguish clustered index rows from nonclustered index rows by their size.

...................................................

Now suppose we have the same table with 100 rows and nonclustered index on the same Col1 column. Now we make an update of id column of this heap.

If you check now sys.dm_tran_version_store you'll see only 10 rows, they are 10 rows of a heap, there is no index rows at all. This is because our index on Col1 was not changed when we updated 10 id. Our id in this case has no affect on nonclustered index that has RID as back pointer to a heap at the leaf level.

Of course if our nonclustered index had id as key field or included field, update of id would affect this index too, in this case we'd found 20 rows in row version store again.

...................................................

Example N3: table with structure Col1, Col2, Col3.
Indexes: ix_1 (Col1), ix_3(Col3).

We update Col2 that is not presented in any index. Only affected rows of the table will get row version tags, ix_1 and ix_3 will not be affected at all.

As Solomon Rutzky pointed out in his comment, these version tags will be presented in indexes until INDEX REBUILD.

Below is the cite from this book: Pro SQL Server Internals By Dmitri Korotkevitch


  Optimistic isolation levels contribute to index fragmentation. When a
  row is modified, SQL Server increases the row size by 14 bytes due to
  the versioning tag pointer. If a page is tightly packed and a new
  version of the row does not fit into the page, it will lead to a page
  split and further fragmentation. This is very similar to the
  insert/update pattern we discussed in Chapter 6, “Index
  Fragmentation.” Those 14 bytes will stay in the row, even after
  records are removed from the version store, until the index is
  rebuilt. 
  
  If optimistic isolation levels are used, it is recommended that you
  reserve some space on the pages by using a  FILLFACTOR  of less than
  100. It reduces page splits due to row-size increases because of the version store pointers.