Still, interesting work. In pure analytic workloads, you typically avoid joins like the plague and lay out the data "pre joined" in a sense (you need a custom query engine usually, not using a relational model as is), so you can avoid jumping around the data, which is what kills you about joins.
Usually when joining, one relation goes in order, the other is spread all over, if you keep them close, you can save some seeks, but reduces the universality of the joins (you also need a-priori knowledge of the cardinalities for it to make sense).
Thankfully most real world data has tighter constraints that you can leverage for effect. Usually theoretical models do not contemplate these, thay concern themselves with a wide swath of cases, but if you assume these constraints true, you can typically build faster structures that have ugly -theoretical- worst cases (if the assumptions don't hold) but that in practice you never see.