Joins are used to combine rows from two or more tables, and come in several types: inner joins return rows where the joined columns match, outer joins also return non-matching rows, and self joins allow a table to be joined with itself. The optimizer chooses between nested loops, hash, sort-merge, and other join methods based on selectivity and cardinality statistics. Indexes like bitmap indexes can improve performance of certain joins.