2010-08-05 17 views
8

Una domanda generale, senza un caso specifico in mente, è solitamente preferibile utilizzare le stored procedure MySQL rispetto alla scrittura di uno script PHP che esegue gli stessi calcoli e le stesse query?MySQL stored procedure o codice php?

Quali sono i vantaggi di ciascun metodo?

+1

Questo argomento SO è rilevante, anche se sta utilizzando lo stack C#/MSSQL. La domanda è la stessa: stored procedure o SQL dinamico: http://stackoverflow.com/questions/15142/what-are-the-pros-and-cons-to-keeping-sql-in-stored-procs-versus- codice – leepowers

+1

Molto da vedere per entrambi i campi. Non è un caso chiaro per entrambi. – Wrikken

+0

Lettura consigliata: http://www.paragoncorporation.com/ArticleDetail.aspx?ArticleID=28 – NullUserException

risposta

0

Ove possibile, l'utente finale trarrà vantaggio dall'astrazione dei dati dall'interfaccia utente. Pertanto, dovresti provare a sfruttare le stored procedure il più possibile.

+0

Vecchia risposta lo so. Tuttavia, ritengo che sia necessario giustificare la tua posizione secondo cui un utente finale, qualcuno che non dovrebbe mai vedere il tuo codice né preoccuparsi di come è stato implementato, trarrà vantaggio da QUALSIASI astrazione, indipendentemente da dove si trovi. – NotMe

+0

L'astrazione consente l'ottimizzazione delle query di dati in modo che l'utente finale tragga vantaggio da un tempo di caricamento più rapido. Non sono sicuro che sia necessaria una spiegazione più approfondita a questa data tardiva. – websch01ar

2

Procedura memorizzata 99 volte su 100. Se fossi il topick 1 motivo, allora sarebbe che se la tua app web php accede a tutti i database tramite stored procedure e l'utente del database ha solo la possibilità di eseguire tali stored procedure allora sei Protetto al 100% da attacchi di iniezione SQL.

0

Non è necessario necessariamente i valori sottostanti se i calcoli vengono eseguiti sul database, quindi lasciare che vengano eseguiti dal database. Ciò aiuta a mantenere al minimo il volume del trasferimento di dati tra il database e uno script PHP; ma generalmente i calcoli con i dati del database vengono eseguiti al meglio dal database stesso.

0

Ho sentito persone dire "lasciare che il database faccia il massimo possibile" e altri hanno pianto come "wtf, cosa stai facendo alle prestazioni del mio database".

Quindi immagino che dovrebbe essere principalmente una decisione del tasso di utilizzo (le stored procedure metteranno in risalto il processo MySQL e il codice PHP sottolineerà il processo del server web).

+2

Bene, le stored procedure non significano necessariamente molto più carico, e se sono sotto il controllo di un DBA c'è meno possibilità che un codificatore anomalo stia stressando il database fino a quando il DBA non ha trovato il problema, ha rimproverato il codice e corretto esso. Più di una grande cosa progetto/dipartimenti però. – Wrikken

2

Per quanto mi riguarda, il vantaggio di mantenere tutto ciò che riguarda il database all'interno del database è il debug. Se i tuoi calcoli (almeno la maggior parte di essi) sono eseguiti all'interno della stored procedure e devi apportare una modifica, devi solo modificarla, verificarla, salvarla. Non ci sarebbero state modifiche al tuo codice PHP.

Se si memorizzano calcoli importanti all'interno del codice PHP, è necessario prendere le istruzioni SQL dal codice, pulirlo, quindi modificarlo, testarlo e quindi copiarlo nuovamente e testarlo di nuovo.

La facilità di manutenzione viene in mente mantenendo le cose separate. Il codice sembra più pulito ed è più facile da leggere se si utilizzano stored procedure, perché sappiamo tutti che gli script SQL diventano incredibilmente grandi. Mantieni tutta la logica del database nel database.

Se il database è correttamente sintonizzato, probabilmente avrete tempi leggermente più rapidi per l'esecuzione della query, perché piuttosto che avere PHP analizzare la stringa, quindi inviarlo al database, quindi il database lo esegue e lo invia indietro , puoi semplicemente inserire parametri nel database con la stored procedure, avrà un piano di esecuzione memorizzato nella cache per la stored procedure e le cose saranno leggermente più veloci. Alcuni indici accuratamente posizionati possono contribuire ad accelerare il recupero dei dati perché in realtà - il server Web è solo un conduit e gli script PHP non lo caricano più di tanto.

1

Direi "non creare troppa magia con il database". Il caso peggiore sarebbe che un nuovo sviluppatore del progetto notasse che ** un'operazione ** è stata eseguita, ma non può vedere dove si trova nel codice. Così continua a cercarlo. Ma è fatto nel database.

Quindi, se si eseguono alcune operazioni di database "invisibili" (sto pensando a trigger), è sufficiente scriverlo nella documentazione del codice.

// add a new user 
$user = new User("john", "doe"); 
$user->save(); 
// The id is computed by the database see MYPROC_ID_COMPUTATION 
print $user->getId(); 

Nell'altra mano, scrittura di funzioni per il DB è una buona idea, e fornirebbe lo sviluppatore un buon livello di astrazione.

// Computes an ID for the given user 
DB->execute("SELECT COMPUTE_ID(" . $user->getLogin() . ") FROM DUAL"); 

Naturalmente questo è tutto pseudo-codice, ma spero tu capisca la mia idea oscura.

+2

Questo potrebbe essere supponendo e chiedendo troppe persone, ma uno sviluppatore non sarebbe in grado di determinare se qualcosa stava eseguendo un proc memorizzato nel database, o una funzione che eseguiva alcune istruzioni SQL generate dinamicamente? Per inciso, nessuna applicazione o operazione di database sarebbe invisibile se ci fosse una documentazione adeguata con esso. Il commento sottolineando la generazione dell'ID sarebbe sufficiente a sospettare. –

4

penso Jeff Atwood ha colpito il chiodo sulla testa nel 2004 per quanto riguarda stored procedure:

Who Needs Stored Procedures, Anyways?

aver usato entrambe le stored procedure e SQL dinamico ampiamente Io sicuramente preferisco il secondo: più facile da gestire, meglio incapsulamento , no BL nel livello di accesso ai dati, maggiore flessibilità e molto altro. Praticamente tutti i principali progetti PHP open-source utilizzano SQL dinamico su proc stored (vedi: Drupal, Wordpress, Magento e molti altri).

Questa conversazione sembra quasi arcaica: prenditi un good ORM, smetti di preoccuparti dell'accesso ai dati e inizia a creare applicazioni fantastiche.

+2

È più facile per me pubblicare la mia dissezione di "Chi ha bisogno di procedure memorizzate, comunque?" in una risposta wiki alla domanda originale. "Good ORM" è un ossimoro –

+0

@OMG Ponies: richiesta tardiva scusami ... hai un link a questo per favore? – gbn

+2

@gbn: [è ciò che desideri] (http://stackoverflow.com/questions/3419604/mysql-stored-procedures-or-php-code/3452048#3452048)? –

1

Beh, c'è un lato di questo argomento che ho molto raramente sentito, quindi mi scrivere qui ...

Codice è la versione controllata. I database non lo sono. Quindi se hai più di un'istanza del tuo codice, avrai bisogno di un qualche modo per eseguire le migrazioni automagicamente al momento dell'aggiornamento o rischi di rompere le cose. E anche con questo, si affrontano ancora i problemi del "dimenticare" per aggiungere un SP aggiornato allo script di migrazione e quindi rompere una build (potenzialmente senza nemmeno rendersene conto se non si sta testando REALMENTE ide).

Da debug e manutenzione, trovo SP 100x tanto difficile da analizzare come SQL raw. Il motivo è che richiede almeno tre passaggi. Per prima cosa, guarda nel codice PHP per vedere quale codice viene chiamato. Quindi vai nel database e trova quella procedura. Poi finalmente guarda il codice della procedura.

Un altro argomento (sulla falsariga del controllo della versione), non esiste un comando svn st per gli SP. Quindi, se si ottiene uno sviluppatore che modifica manualmente un SP, si avrà un sacco di tempo a capirlo (supponendo che non siano tutti gestiti da un singolo DBA).

Dove lo SP rappresenta davvero lo splendore quando più applicazioni parlano allo stesso schema di database. Quindi, hai solo un posto in cui sono archiviati DDL e DML e entrambe le applicazioni possono condividerli senza dover aggiungere una dipendenza incrociata in una o più librerie.

Così, in breve, la mia opinione è la seguente:

utilizzare le stored procedure:

  1. Quando si dispone di più applicazioni che lavorano fuori lo stesso insieme di dati
  2. Quando si ha la necessità di un ciclo su effettua query ed esegue altre query (evitando che le perdite di livello TCP possano migliorare in modo GRANDE l'efficienza)
  3. Se si dispone di un DBA veramente, poiché imporrà tutto il codice SQL gestito da lui/lei.

Usa grezzo SQL/ORM/SQL generato quasi in ogni altro caso (Quasi, dal momento che ci sono tenuti ad essere casi limite non sto pensando a) ...

Ancora una volta, questo è solo il mio $ 0,02 ...

+0

Non stai memorizzando i tuoi script db nel controllo della versione? Tsk, tsk. –

+0

Per sapere quale proc è stato modificato: in sql 2005+ è possibile utilizzare qualcosa come: SELECT nome FROM sys.objects WHERE type = 'P' AND DATEDIFF (D, modify_date, GETDATE()) <7. – NotMe

3

Per noi l'utilizzo di stored procedure è assolutamente fondamentale. Abbiamo un'app .net abbastanza grande. Per ridistribuire l'intera app è possibile che i nostri utenti siano offline per un breve periodo che semplicemente non è consentito.

Tuttavia, mentre l'applicazione è in esecuzione, a volte è necessario apportare correzioni minori alle nostre query. Cose semplici come aggiungere o rimuovere un NOLOCK, o forse anche cambiare i join coinvolti. È quasi sempre per motivi di prestazioni. Proprio oggi abbiamo avuto un errore causato da un NOLOCK estraneo. 2 minuti per individuare il problema, determinare la soluzione e distribuire il nuovo proc: tempo di fermo pari a zero. Fare ciò con le query nel codice avrebbe causato almeno un'interruzione di minore entità potenzialmente incazzare un sacco di persone.

Un'altra ragione è la sicurezza. Con proc's passiamo l'id utente (non sequenziale, non immaginabile) in ogni chiamata proc. Convalidiamo che l'utente ha accesso per eseguire quella funzione nell'app Web e di nuovo all'interno del database stesso. Questo solleva radicalmente la barriera per gli hacker se la nostra app Web è stata compromessa. Non solo non potevano eseguire nessuno sql che volevano, ma anche per eseguire un proc avrebbero dovuto avere una particolare chiave di autorizzazione. Che sarebbe difficile da acquisire. (e no non è la nostra unica difesa)

Abbiamo il controllo del codice sorgente del nostro proc, quindi non è un problema. Inoltre, non devo preoccuparmi di come nomino le cose (alcuni ORM odiano certi schemi di denominazione) e non devo preoccuparmi delle prestazioni di volo. Devi conoscere molto più di un semplice SQL per regolare in modo appropriato un ORM. Devi conoscere i comportamenti particolari dell'ORM.

10

Point/Counter Point con Jeff Atwoods "Who Needs Stored Procedures, Anyways?" from 2004:

1) stored procedure sono scritte in ferro grande database di "linguaggi" come PL/SQL (Oracle) o T-SQL (Microsoft). Questi cosiddetti linguaggi sono arcaici e pieni di pazzi, incoerenti scelte progettuali che derivano sempre dalla tortuosa evoluzione di dieci anni di retrocompatibilità. Non vuoi davvero scrivere molto codice in questa roba. Per il contesto, JavaScript è un passo da gigante di PL/SQL o T-SQL.

Risposta: La "S" in "SQL" significa "strutturato", non "standardizzata" - PLSQL e TSQL sono entrambi personalizzati estensioni di SQL, che portano anche ANSI SQL in gioco, perché c'è molto poco SQL che è indipendente dal database. In genere, se si desidera una query che funzioni bene, lo non può fare affidamento su ANSI SQL.

L'ORM non è un proiettile argentato: a causa dell'astrazione del database, la maggior parte del supporto esegue le procedure/le stored procedure native per ottenere una query ben funzionante. Che è bello, ma sconfigge completamente lo scopo di ORM ...

Non capirò mai perché lo sviluppo web, un intreccio di innumerevoli tecnologie (HTML, Javascript/AJAX, Flash ...) segrega sempre SQL come il nero pecore della famiglia. Come tutti gli altri, devi imparare per ottenere qualcosa da esso. Deve essere la gratificazione immediata che si ottiene quando si utilizzano le altre tecnologie ...

2) Le stored procedure in genere non possono essere debuggate nello stesso IDE in cui si scrive l'interfaccia utente. Ogni volta che isolare un'eccezione nei proc, devo interrompere quello che sto facendo, rilasciare la mia copia di Toad e caricare i pacchetti del database per vedere cosa non funziona. La transizione frequente tra due IDE totalmente diversi, con interfacce e linguaggi completamente diversi, non è esattamente produttiva.

Risposta: non era in origine un debugger JavaScript in Eclipse o Visual Studio? No, consentono i plug-in per far uscire il prodotto dalla porta & rinvigoriscono un mercato precedentemente inesistente. La maggior parte non ha problemi a usare Firebug al di fuori di Visual Studio/Eclipse, perché il debug SQL dovrebbe essere diverso?

3) Le stored procedure non forniscono molto feedback quando le cose vanno male. A meno che il proc non sia codificato internamente con una strana gestione di eccezioni T-SQL o PL/SQL, otteniamo "errori" criptici restituiti in base alla particolare riga all'interno del proc non riuscita, come la tabella non ha righe. Uh, ok?

Risposta: La vostra mancanza di familiarità non lo fa un povero make lingua. Come se non avessi mai dovuto google per uno strano errore nella tua lingua preferita ... Almeno Oracle & MySQL ti fornisce i numeri di riferimento degli errori.

4) Le stored procedure non possono passare oggetti. Quindi, se non stai attento, puoi finire con un parametro di zillion. Se devi compilare una riga della tabella con 20+ campi usando un proc, dì ciao a 20+ parametri. Peggio ancora, se passo un parametro negativo - troppi, non sufficienti, o cattivi tipi di dati - ottengo un errore generico di "cattiva chiamata". Oracle non può dirmi quali parametri sono in errore! Quindi devo pori oltre 20 parametri, a mano, per capire quale è il colpevole.

Risposta: SQL è impostato in base, completamente a differenza di programmazione procedurale/OO. I tipi sono vicini agli oggetti, ma a un certo punto ci deve essere una mappatura tra oggetti procedurali/OO e entità di database.

5) Le stored procedure nascondono la logica aziendale. Non ho idea di cosa stia facendo un proc, o che tipo di cursore (DataSet) o valori restituirà a me. Non riesco a visualizzare il codice sorgente sul proc (almeno, senza ricorrere al n. 2 se ho un accesso appropriato) per verificare che stia effettivamente facendo quello che penso sia - o che il progettista intendesse fare. Inline SQL potrebbe non essere carina, ma almeno posso vederlo nel contesto, insieme alla logica del business.

Risposta: Questa è una buona cosa (tm) - è così che si ottiene Model-View-Controller (MVC), in modo da poter avere un front-end in una moltitudine di lingue senza dover duplicare la logica ogni volta affrontando le stranezze di ogni lingua per replicare quella logica. O è positivo che il database consenta l'aggiunta di dati errati se qualcuno si collega direttamente al database? Ritorna indietro & avanti tra l'applicazione e il tempo di spreco del database & risorse che l'applicazione non potrà mai recuperare.

+1

avevo quasi perso spero per questa domanda fino a quando ho visto la tua risposta. +1 –

1

Uso le stored procedure il più possibile per una serie di motivi.

Ridurre round trip al database

Se è necessario modificare più tabelle correlate in una sola volta, quindi è possibile utilizzare un singolo stored procedure in modo che è fatta solo una chiamata al database.

definire chiaramente la logica di business

Se certe cose devono essere vere su una query, quindi una procedura di memorizzazione permette di qualcuno che conosce SQL (un linguaggio abbastanza semplice) assicurano che le cose sono fatte bene.

Creare semplici interfacce per altri programmatori

I suoi compagni di squadra competenti non SQL possono utilizzare interfacce molto più semplice per il database e si può essere certi che non possono mettere le relazioni in cattivo stato in incidente.

considerare:

SELECT a.first_name, IFNULL(b.plan_id, 0) AS plan_id 
FROM account AS a 
    LEFT JOIN subscription AS s ON s.account_id = a.id 
WHERE a.id = 23 

Rispetto a:

CALL account_get_current_plan_id(23); 

scrivere loro un bel po 'involucro di prendersi cura di gestire le chiamate di stored procedure e sono nel mondo degli affari.

aggiornamento tutti gli utilizzi in un sistema in una volta

Se tutti usano le stored procedure per interrogare il database ed è necessario cambiare come funziona qualcosa, è possibile aggiornare la stored procedure e viene aggiornato ovunque il più a lungo non cambi l'interfaccia.

sicurezza forzate

Se è possibile utilizzare solo le stored procedure di fare tutto all'interno del vostro sistema, allora si può dare i permessi seriamente limitate all'account utente che accede ai dati. Non c'è bisogno di dare loro le autorizzazioni UPDATE, DELETE o SELECT.

facile movimentazione

Molte persone non si rendono conto dell'errore, ma è possibile creare le stored procedure in modo tale che la maggior parte dei problemi rintracciare diventa molto facile.

È anche possibile integrare il codice base per gestire correttamente gli errori restituiti se si utilizza una buona struttura.

Ecco un esempio che fa il seguente:

  • utilizza un gestore di uscita per problemi seri
  • Utilizza un gestore di proseguire per problemi meno gravi
  • Fa non tabella di convalida di scansione in attacco
  • Verifica di scansione della tabella successiva se la convalida non è fallita
  • Esegue l'elaborazione in una transazione se le cose convalidano
  • rollback tutto se c'è un problema
  • segnala eventuali problemi riscontrati
  • Evita aggiornamenti inutili

Qui è la struttura interna di una stored procedure costituito che accetta un ID account, l'account chiusura id, e un indirizzo IP e quindi li utilizza per aggiornare in modo appropriato. Il delimitatore è già stato impostato su $$:

BEGIN 

     # Helper variables 

     DECLARE r_code INT UNSIGNED; 
     DECLARE r_message VARCHAR(128); 
     DECLARE it_exists INT UNSIGNED; 
     DECLARE n_affected INT UNSIGNED; 

     # Exception handler - for when you have written bad code 
     # - or something really bad happens to the server 
     DECLARE EXIT HANDLER FOR SQLEXCEPTION 
     BEGIN 
      ROLLBACK; 
      SELECT 0 as `id`, 10001 as `code`, CONCAT(r_message, ' Failed with exception') as `message`; 
     END; 

     # Warning handler - to tell you exactly where problems are 
     DECLARE CONTINUE HANDLER FOR SQLWARNING 
     BEGIN 
      SET r_code = 20001, r_message = CONCAT(r_message, 'WARNING'); 
     END; 

     SET r_code = 0, r_message = '', it_exists = 0, n_affected = 0; 

     # STEP 1 - Obvious basic sanity checking (no table scans needed) 
     IF (0 = i_account_id) THEN 
      SET r_code = 40001, r_message = 'You must specify an account to close'; 
     ELSEIF (0 = i_updated_by_id) THEN 
      SET r_code = 40002, r_message = 'You must specify the account doing the closing'; 
     END IF; 

     # STEP 2 - Any checks requiring table scans 

     # Given account must exist in system 
     IF (0 = r_code) THEN 
      SELECT COUNT(id) INTO it_exists 
      FROM account 
      WHERE id = i_account_id; 

      IF (0 = it_exists) THEN 
       SET r_code = 40001, r_message = 'Account to close does not exist in the system'; 
      END IF; 
     END IF; 

     # Given account must not already be closed 
     # - if already closed, we simply treat the call as a success 
     # - and don't bother with further processing 
     IF (0 = r_code) THEN 
      SELECT COUNT(id) INTO it_exists 
      FROM account 
      WHERE id = i_account_id AND status_id = 2; 

      IF (0 < it_exists) THEN 
       SET r_code = 1, r_message = 'already closed'; 
      END IF; 
     END IF; 

     # Given closer account must be valid 
     IF (0 = r_code) THEN 
      SELECT COUNT(id) INTO it_exists 
      FROM account 
      WHERE id = i_updated_by_id; 
     END IF; 

     # STEP 3 - The actual update and related updates 
     # r-message stages are used in case of warnings to tell exactly where a problem occurred 
     IF (0 = r_code) THEN 
      SET r_message = CONCAT(r_message, 'a'); 

      START TRANSACTION; 

      # Add the unmodified account record to our log 
      INSERT INTO account_log (field_list) 
      SELECT field_list 
      FROM account 
      WHERE id = i_account_id; 

      IF (0 = r_code) THEN 
       SET n_affected = ROW_COUNT(); 
       IF (0 = n_affected) THEN 
        SET r_code = 20002, r_message = 'Failed to create account log record'; 
       END IF; 
      END IF; 

      # Update the account now that we have backed it up 
      IF (0 = r_code) THEN 
       SET r_message = CONCAT(r_message, 'b'); 

       UPDATE account 
       SET 
        status_id = 2, 
        updated_by_id = i_updated_by_id, 
        updated_by_ip = i_updated_by_ip 
       WHERE id = i_account_id; 

       IF (0 = r_code) THEN 
        SET n_affected = ROW_COUNT(); 
        IF (0 = n_affected) THEN 
         SET r_code = 20003, r_message = 'Failed to update account status'; 
        END IF; 
       END IF; 
      END IF; 

      # Delete some related data 
      IF (0 = r_code) THEN 
       SET r_message = CONCAT(r_message, 'c'); 

       DELETE FROM something 
       WHERE account_id = i_account_id; 
      END IF; 

      # Commit or roll back our transaction based on our current code 
      IF (0 = r_code) THEN 
       SET r_code = 1, r_message = 'success'; 
       COMMIT; 
      ELSE 
       ROLLBACK; 
      END IF; 
     END IF; 

     SELECT 
      r_code as `code`, 
      r_message as `message`, 
      n_affected as `affected`; 

    END$$ 

significati codice di stato:

  • 0: non dovrebbe mai accadere - cattivo risultato
  • 1: successo - il conto è stato sia già chiuso o correttamente chiusa
  • 2xxxx - problemi di logica o sintassi
  • 3xxxx - problemi con valori di dati imprevisti nel sistema
  • 4XXXX - campi mancanti mancanti

Piuttosto che fidarsi dei programmatori che non hanno familiarità con i database (o semplicemente non hanno familiarità con lo schema), è molto più semplice fornire loro interfacce.

Invece di fare tutti i controlli di cui sopra, si può semplicemente utilizzare:

CALL account_close_by_id(23); 

e quindi controllare il codice risultato e prendere i provvedimenti opportuni.

Personalmente, credo che se si ha accesso alle stored procedure e non le si sta utilizzando, allora dovresti davvero utilizzarle.

Problemi correlati