progettare - mysql tutorial italiano



Progettare le relazioni attorno a una struttura ereditaria (1)

Ho una domanda concettuale su come organizzare al meglio il mio database.

Attualmente ho quattro tabelle principali users , teachers , students e notifications . Comunque sia le tabelle degli teachers che degli students ereditano dalla tabella degli users , quindi contengono la chiave esterna user_id .

La tabella delle notifications come potresti aver intuito fa riferimento alle notifiche. Questi devono apparire per tutti gli utenti che appartengono a un gruppo di dipendenti, cioè sotto l'occupazione di un altro.

Sia gli studenti che gli insegnanti possono assumere altri utenti.

Quindi il punto cruciale è che ho bisogno di un modo eloquente di modellarlo. Il flusso di lavoro di base del codice sarebbe il seguente:

getCurrentUser->getAllEmployer(s)->getNotifications

Questo è il Laravel Eloquent che sono abituato a $user->employers()->notifications;

Sfortunatamente non è così semplice come in questo caso un datore di lavoro può fare riferimento a due tabelle.

Quindi le mie scelte sono le seguenti.

  1. Creare una relazione eloquente per entrambi i rapporti tra student e teacher come datori di lavoro. Il deficit è che ho bisogno di scrivere se i test per verificare se l'utente corrente appartiene a entrambi e questo codice sarebbe ripetuto frequentemente.
  2. Aggiungi un teacher_id e uno student_id alla tabella degli users . Tuttavia, uno sarebbe ovviamente ridondante in ogni record. La possibilità di dover aggiungere altre colonne è molto probabile anche a causa dell'emergere di nuove entità di datori di lavoro.
  3. Creare una tabella employer_employee che contiene due colonne che fanno riferimento a un user_id . Una query SQL avrebbe SINISTRA le tabelle degli student e degli teacher con la tabella employer_employee e quindi un JOIN con le notifications restituirebbe tutte quelle pertinenti. Tuttavia, così tanti join riducono la velocità della query rispetto alle altre opzioni.
  4. Qualcosa che non ho considerato.

Sto davvero cercando la soluzione più efficiente e scalabile .

Qualsiasi aiuto è apprezzato. Se potessi chiarire perché la tua risposta è la soluzione scalabile più efficiente, sarebbe superba.


C'è una domanda simile qui usando un supertipo di Media e aggiungendo sottotipi di CD, VCR, DVD, ecc.

Questo è scalabile in quanto creando, per esempio, un sottotipo BluRay, si crea la tabella per contenere i dati specifici di BluRay e si aggiunge una voce alla tabella MediaTypes. Nessuna modifica necessaria per dati o codice esistenti, ad eccezione, ovviamente, per aggiungere il codice che funzionerà con i dati BluRay.

Nel tuo caso, gli utenti sarebbero la tabella dei supertipi con insegnanti e studenti nelle tabelle dei sottotipi.

create table Users(
    ID      int not null auto_generating,
    Type    char( 1 ) check( Type in( 'T', 'S' )),
    -- other data common to all users,
    constraint PK_Users primary key( ID ),
    constraint UQ_UserType unique( ID, Type ),
    constraint FK_UserTypes foreign key( Type )
        references UserTypes( ID )
);
create table Teachers(
    TeacherID int not null,
    TeacherType char( 1 ) check( TeacherType = 'T' )),
    -- other data common to all teachers...,
    constraint PK_Teachers primary key( TeacherID ),
    constraint FK_TeacherUser foreign key( TeacherID, TeacherType )
        references Users( ID, Types )
);

La composizione del tavolo Studenti sarebbe simile alla tabella Insegnanti.

Poiché sia ​​gli insegnanti che gli studenti possono assumere altri insegnanti e studenti, la tabella che contiene questa relazione farebbe riferimento alla tabella Utenti.

create table Employment(
    EmployerID    int not null,
    EmployeeID    int not null,
    -- other data concerning the employment...,
    constraint CK_EmploymentDupes check( EmployerID <> EmployeeID ),
    constraint PK_Employment primary key( EmployerID, EmployeeID ),
    constraint FK_EmploymentEmployer foreign key( EmployerID )
        references Users( ID ),
    constraint FK_EmploymentEmployee foreign key( EmployeeID )
        references Users( ID )
);

A quanto ho capito, le notifiche sono raggruppate dal datore di lavoro:

create table Notifications(
    EmployerID    int not null
    NotificationDate date,
    NotificationData varchar( 500 ),
    -- other notification data...,
    constraint FK_NotificationsEmployer foreign key( EmployerID )
        references Users( ID )
);

Le domande dovrebbero essere abbastanza semplici. Ad esempio, se un utente desidera vedere tutte le notifiche dei suoi datori di lavoro:

select  e.EmployerID, n.NotificationDate, n.NotificationData
from    Employment  e
join    Notifications n
    on  n.EmployerID = e.EmployerID
where   e.EmployeeID = :UserID;

Questo è uno schizzo iniziale, ovviamente. I perfezionamenti sono possibili. Ma ai tuoi punti numerati:

  1. Il tavolo sull'occupazione riporta i datori di lavoro ai dipendenti. L'unico controllo è se i datori di lavoro degli utenti non possono essere i dipendenti stessi, ma altrimenti qualsiasi utente può essere sia un dipendente che un datore di lavoro.
  2. La tabella Utenti obbliga ogni utente a essere un insegnante ("T") o uno studente ("S"). Solo gli utenti definiti come "T" possono essere inseriti nella tabella Insegnanti e solo gli utenti definiti come "S" possono essere inseriti nella tabella Studenti.
  3. La tabella Employment si unisce solo alla tabella Users, non alle tabelle Teachers e Students. Ma questo perché sia ​​gli insegnanti che gli studenti possono essere sia datori di lavoro che dipendenti, non per ragioni di prestazione. In generale, non preoccuparti delle prestazioni durante la progettazione iniziale. La tua preoccupazione principale a questo punto è l'integrità dei dati. I database relazionali sono molto buoni con i join. Se dovesse sorgere un problema di prestazioni, correggilo. Non ristrutturare i dati per risolvere problemi che ancora non esistono e potrebbero non esistere mai.
  4. Bene, provalo e vedi come funziona.




relational-database