Query SQL o codice C # .net per l'importazione di file csv?

2

Il mio scopo qui è di trovare la soluzione migliore e fattibile per il mio dilemma. Voglio importare qualche file csv (può contenere circa 50 ~ 60K record) nel database dopo qualche manipolazione nei file, la manipolazione include il confronto come un record già esistente nel database o meno. Ho già un'applicazione .net c # che

  • ottiene il file
  • recupera i dati in datatable
  • effettua il ciclo di ogni record, effettua il confronto per ogni record dal database
  • e infine aggiorna / crea / elimina record.

questo intero processo apparentemente richiede troppo tempo. Il mio cliente ha bisogno che questo processo funzioni il più velocemente possibile. Gli ho suggerito di eseguire questo processo di importazione solo con SQL (anche se non sono sicuro che funzionerebbe in modo più efficiente utilizzando funzionalità SQL come la tabella di staging, la tabella temporanea ei cursori).

Ora per SQL questo è quello che pensavo potesse essere fatto per farlo funzionare meglio:

  • crea una tabella di staging
  • utilizzando la funzione BULK IMPORT o SQLBULKCOPY importa tutti i dati del file csv in questa tabella di staging.
  • crea un SP che passa in rassegna (usando CURSOR ofcourse) tutti i record dalla tabella di staging e confronterà ogni record dalla tabella db già esistente e creerà / aggiornerà / eliminerà il record di conseguenza.
  • tabella di staging vuota.

Non sono sicuro che la versione SQL funzionerebbe in modo più efficiente nel mio caso o meno. In totale non sono in grado di vedere una visione chiara del fatto che dovrei andare con la versione SQL della soluzione o attenermi all'attuale codice .net C # e ottimizzare solo questo codice corrente. Sarebbe bello se qualcuno mi potesse consigliare sullo stesso.

lascia che ti spieghi questo con l'aiuto di un esempio:

  1. questi sono gli header del file csv: StudentId, StudentFname, StudentLname, ClassName, teacherId, teacherFname, teacherLname
  2. Supponiamo di aver copiato tutti i suoi dati così come sono nella tabella di staging.
  3. ora devo aggiornare quegli studenti che sono già nella tabella STUDENT e creare quelli che non esistono, controllare se il nome della classe esiste già nella tabella CLASS (se non è quindi creare la classe), controllare se l'ID insegnante esiste già in Tabella INSEGNANTE (se non lo è, crea l'insegnante, altrimenti aggiornalo).
posta Shilpa Soni 19.02.2016 - 10:49
fonte

2 risposte

2

I server SQL offriranno prodotti specifici come DTS o SSIS per l'importazione di dati. Questi possono essere abbastanza ottimizzati e funzionare molto rapidamente.

Tuttavia !! Se hai competenze di programmazione ti raccomando caldamente di scrivere il tuo software di importazione.

La ragione di ciò è che, sebbene il server Sql possa essere in grado di eseguire un processo di importazione più velocemente in un caso migliore, è intrinsecamente non scalabile.

Se si scrive il proprio importatore, è possibile spostare tutta la logica e il file in lettura su un server separato e caricare solo la casella sql con scritture semplici. Ciò ti consente di ridimensionare orizzontalmente.

I database SQL sono uno dei principali punti dolenti durante il ridimensionamento e il modo per minimizzare questo è quello di mantenere tutta la logica aziendale fuori dagli schemi. Ho visto sistemi con una logica di programmazione complicata che ha esaurito le ore del giorno per importare i file, eseguendo una finestra sql con specifiche al 100% 24/7

Inoltre, sebbene gli strumenti Dile / SSIS siano adatti per gli amministratori di database che desiderano eseguire il dispari compito di "programmazione". Cadono bene dietro le caratteristiche di un moderno stack di devops, come il versioning, il debug, nessuna distribuzione downtime, etc etc

    
risposta data 20.02.2016 - 12:02
fonte
1

Non sei sicuro di averlo risolto ora. Sono d'accordo che la rotta SQL è probabilmente la strada da percorrere, ma penso che la tua domanda principale sia il modo migliore in T-SQL per confrontare i dati di staging con la tabella di destinazione e inserire / aggiornare secondo necessità, giusto? Penso che il ciclo finirebbe per essere relativamente lento per questo scenario. Vorrei usare un MERGE per gli studenti, come ha detto Keith Miller, e solo INSERTI regolari per classe e insegnante. Per fare un esempio, ho fatto alcune supposizioni sul tuo modello di dati, come la tabella Student con un campo ClassId e TeacherId.

INSERT INTO Teacher
SELECT  DISTINCT
        teacherId,
        teacherFname,
        teacherLname
FROM    StagingTable st
WHERE   NOT EXISTS (SELECT * FROM Teacher t WHERE t.teacherId = st.teacherId) 

INSERT INTO Class
SELECT  DISTINCT
        ClassName
FROM    StagingTable st
WHERE   NOT EXISTS (SELECT * FROM Class c WHERE c.ClassName = st.ClassName)

-- CTE here is optional, if you have a way to narrow the list of students to compare. 
-- For example, maybe the import file is for a specific school
; WITH StudentsCte AS
(
    SELECT  *
    FROM    Student
    WHERE   School = @school
)
MERGE StudentsCte AS Target
USING
    (
        SELECT  StudentId,
                StudentFName,
                StudentLName,
                ClassId,
                TeacherId
        FROM    StagingTable st
                INNER JOIN Class c ON c.ClassName = st.ClassName
    ) AS Source
ON Target.StudentId = Source.StudentId

WHEN MATCHED AND 
    (
        -- Optional comparisons to only update if something changed
        ISNULL(StudentFName, '') <> ISNULL(Source.StudentFName, '')
        -- OR (compare all fields)
    ) THEN 
    UPDATE SET 
        StudentFName = Source.StudentFName,
        ClassId = Source.ClassId
        -- other fields 

WHEN NOT MATCHED BY Target THEN
    INSERT (StudentFName, StudentLName, School, ClassId, TeacherId)
    VALUES (Source.StudentFName, Source.StudentLName, @school, ClassId, TeacherId)

WHEN NOT MATCHED BY Source THEN
    DELETE
    -- Or do a soft delete instead if the table has a flag like this: UPDATE SET IsDeleted = 1

Questo dovrebbe essere modificato a seconda del tuo schema e delle tue relazioni. Ad esempio, se si utilizzano colonne IDENTITY come PK e TeacherId è in realtà un numero alfanumerico interno esclusivo per gli insegnanti (numero impiegato, nome di accesso, ecc.). In questo caso, lo Student FK to Teacher è probabilmente un campo diverso, e dovresti unirti all'insegnante per ottenere quel valore ID nella definizione Source per l'unione.

    
risposta data 04.03.2016 - 02:29
fonte

Leggi altre domande sui tag