.

.

Bom, esqueça performance nesse caso.
É gambiarra feia, mas aí vai

SELECT
table1.dado1, table1.dado2, table1.dado3,
table2.info3, table5.detalhe8
FROM
table1,
table2,
table5
WHERE
table1.dado1 = parametro1
AND
table1.dado2 = table2.info3
AND
table5.detalhe8 = parametro2;

.

É um exemplo.
Suponha que você precise achar os dados de 3 tabelas, sem a bendita FK.
A forma de achar um dado em um SELECT é selecionar tudo de todas as linhas ou passar um parâmetro (ou mais), forçando o SQL a buscar os resultados que se encaixam no que se pesquisa (coluna X registro).
Quando eu coloquei ali os parâmetros 1 e 2, apenas fiz referência a isso.
Pode ver ali que a table1 e a table2 possuem uma FK (no caso, dado2 e info3 tem o mesmo valor em ambas), mas, a table5 está “solta”. Por isso, além do parâmetro normal (ou dos parâmetros normais) da cláusula WHERE, ainda é preciso informar um (ao menos) que identifique os valores requeridos da table5.
Exemplo

SELECT

t1.dado1,
t2.dado1,
t2.dado2,
t3.exceto

FROM
table1 t1,
table2 t2,
table3 t3

WHERE
# e aqui o pulo do gato
t1.dado1 = parametro_que_refina_a_pesquisa
AND
t2.dado2 = t1.dado1
AND
t3.exceto = outro_parametro_que_faz_achar_valores_na_table3;

Claro, o select pode ser

select * from t1, t2, t3; mesmo sendo muito custoso ao banco

.

Os campos duplicados você pode eliminar colocando a keyword DISTINCT no fim da consulta.
Collection, ótima opção.
XML e iReport, sim, trate e voilà…

.