Votre instinct de ne pas créer une grande table avec beaucoup de NULLS est juste. C'est une mauvaise idée, du point de vue du stockage/récupération/maintenance, ainsi que du point de vue de la validation des données (nous en reparlerons plus tard).
Les deux approches les plus courantes :
1) Avoir une table d'utilisateurs avec tous les champs communs, y compris un champ "userType". Ayez ensuite une table distincte pour chaque type d'utilisateur contenant les champs supplémentaires. Tous les utilisateurs ont une ligne dans la table des utilisateurs et une ou plusieurs des tables de type d'utilisateur spécifiques. C'est le plus normalisé et le plus efficace pour le stockage et les connexions rapides. Cela vous permet également d'utiliser des contraintes et des clés étrangères pour vous assurer que toutes les informations requises pour chaque type d'utilisateur sont disponibles.
2) Avoir une table utilisateur avec tous les champs communs qu'elle contient. Avoir une autre table appelée quelque chose comme UserAttributes qui a des champs pour l'ID utilisateur, la clé et la valeur. Toute métadonnée supplémentaire pour un utilisateur particulier peut être stockée ici. Cela a l'avantage de ne nécessiter aucune administration de base de données pour ajouter de nouveaux types d'utilisateurs ou des métadonnées à stocker pour chaque type d'utilisateur. Cependant, il ne vous permet pas de valider les données au niveau de la base de données.