C'est mouvementé comme tout, mais cela devrait vous apporter ce dont vous avez besoin :
SELECT SUM(PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM a.end_date), EXTRACT(YEAR_MONTH FROM a.start_date))) months
FROM (
SELECT MIN(g.start_date) start_date, MAX(g.end_date) end_date
FROM (
SELECT @group_id := @group_id + (@end_date IS NULL OR o.start_date > @end_date) group_id,
start_date,
@end_date := DATE(CASE
WHEN (@end_date IS NULL OR o.start_date > @end_date) THEN o.end_date
ELSE GREATEST(o.end_date, @end_date)
END) end_date
FROM overlap o
JOIN (SELECT @group_id := 0, @end_date := NULL) init
ORDER BY o.start_date ASC
) g
GROUP BY g.group_id
) a
La requête la plus interne regroupe vos périodes dans des groupes qui se chevauchent, étirant la date de fin, le cas échéant. Le end_date fléchit car j'ai supposé qu'il pourrait y avoir des périodes complètement entourées par le précédent.
La requête d'encapsulation suivante extrait la plage complète de chaque groupe.
La requête externe résume les différences mensuelles complètes pour chaque groupe. Tous les diffs de groupe sont arrondis au mois complet le plus proche par PERIOD_DIFF.
Malheureusement, je n'ai pas pu tester cela car SQLFiddle est mort sur moi.