2010-01-28 16 views
7

Sto creando un nuovo database in SQL Server 2008 per alcuni report e ci sono molte regole aziendali comuni relative a questi dati che vanno in diversi tipi di report. Attualmente queste regole sono per lo più combinate in programmi procedurali più grandi, in un linguaggio legacy, che sto cercando di passare a SQL. Sto cercando flessibilità nell'implementazione dei rapporti da questi dati, come alcuni report in SAS, alcuni in C#, ecc.Sto usando SQL UDF per incapsulare semplici report/business logic. Dovrei evitare questo?

Il mio approccio al momento è quello di suddividere queste regole comuni (in genere MOLTO semplice logica) e incapsularle in singoli UDF SQL. Le prestazioni non sono un problema, voglio solo utilizzare queste regole per compilare campi statici in una sorta di "istantanea" di reporting, che può quindi essere utilizzata per segnalare da qualsiasi cosa desideri.

Mi piace questo approccio modulare per quanto riguarda la comprensione di ciascuna regola (e il mantenimento delle regole stesse), ma sto anche iniziando a temere che la manutenzione possa anche diventare un incubo. Alcune regole dipendono dagli altri, ma non posso davvero fuggire da questo: queste cose si costruiscono l'un l'altra ... che è quello che voglio ... penso? ;)

Esistono approcci migliori per questo approccio modulare in un database? Sono sulla buona strada, o sto pensando a questo in troppa mentalità di sviluppo di applicazioni?

+0

Grazie a tutti! Sembra che questo approccio dovrebbe essere OK :) Ancora una volta, le prestazioni non sono un problema con queste perché vengono utilizzate solo una volta per istanza ETL/snapshot. Quindi potrebbe essere necessario un minuto o due o tre per compilare i campi a cui vengono inviate queste funzioni, ma in seguito qualcuno interrogherà sempre solo sulla tabella, mai utilizzando le funzioni in una query. Bene, almeno non dovrebbero usarli! – chucknelson

risposta

1

SQL è impostato in base, e intrinsecamente funziona male quando si applica un approccio modulare.
Funzioni, stored procedure e/o viste: tutti astraggono la logica sottostante. Il problema di prestazioni entra in gioco quando si usano due (o più) funzioni/etc che utilizzano le stesse tabelle. Significa che due query sono fatte le stesse tabelle quando si poteva essere usate.

L'uso di più funzioni mi dice che il modello di dati è stato reso molto "flessibile". Per me, ciò significa digitare dati discutibili e definizione generale di colonne/tabelle. C'è bisogno di funzioni/etc perché il database permetterà di memorizzare qualsiasi cosa, il che significa che la possibilità di dati errati è molto alta.Preferirei fare lo sforzo di avere sempre dati validi/validi, piuttosto che lavorare dopo il fatto per combattere i cattivi dati esistenti.

il database è il posto giusto per contenere questa logica. È più veloce del codice dell'applicazione e, soprattutto, centralizzato per ridurre al minimo la manutenzione.

+0

Sono d'accordo: i dati di base che ottengo sono molto ampi. Fondamentalmente sto trattando il mio processo di "istantanea" come un passo ETL, e usando queste UDF per popolare campi che saranno molto utili da chiunque voglia utilizzare i dati per il reporting (o qualsiasi altra cosa, davvero). – chucknelson

+0

@chucknelson: Capisco: il mio lavoro attuale mi ha comportato in modo simile. –

2

A un certo punto, l'uso estensivo di UDF inizierà a causare problemi di prestazioni poiché vengono eseguiti per ogni riga nel vostro set di risultati e la logica oscura dall'ottimizzatore, rendendo difficile l'uso di indici (cioè non capisco davvero come le prestazioni non possono essere un problema, ma tu conosci meglio le tue esigenze). Per certe funzionalità sono fantastici; ma usali con parsimonia.

+0

Sono completamente d'accordo con questo, ma mi basta usare questi quando prendo un particolare "istantanea" per riempire i campi statici, che sono ciò che qualcuno avrebbe query per qualsiasi scopo di reporting. Altrimenti sposterei sicuramente questa logica nel livello di reporting (e combatterò per un'implementazione di reporting standard), o lavorerò per spostare le cose in funzioni con valori di tabella. Grazie per il feedback, però! – chucknelson

+0

non tutte le UDF vengono eseguite una volta per riga, quelle in linea vengono appiattite dall'ottimizzatore. Le UDF scalari sono davvero molto lente –

+0

La tabella UDF non verrebbe eseguita per ogni riga? – JeffO

1

Direi che siete sulla strada giusta: le procedure SQL possono rapidamente sfuggire di mano mentre le parti di logica condivise e ripetute, sempre più complesse e incapsulanti, sono una soluzione assolutamente appropriata per affrontarle.

Spesso vado fino all'incapsulamento della logica da una procedura sql che viene utilizzata solo in quella procedura in una UDF denominata per migliorare la leggibilità.

Dai un'occhiata a this MSDN article su UDF: forse ti darà qualche idea in più sui loro usi?

Ci sono varie considerazioni sulle prestazioni che è necessario tenere presente se si intende utilizzare in modo approfondito le UDF, ad esempio le prestazioni delle UDF scalari rispetto alle tabelle e i possibili vantaggi delle UDF CLR.

0

Se sei interessato a creare un data warehouse per la segnalazione, proverai a mettere quanto più possibile nella parte di trasformazione del tuo ETL possibile in modo che il report SQL sia composto da semplici istruzioni che gli strumenti e gli utenti sono in grado di generare .

SSIS è uno strumento ETL molto capace fornito con server SQL per questo genere di cose.

+0

Attualmente è uno scopo piuttosto piccolo, ma sono d'accordo, mi piacerebbe utilizzare alcuni strumenti/processi di reporting adeguati per questo. Per ora sto cercando di costruire qualcosa di gestibile e facile da leggere/capire per una futura generazione;) – chucknelson

2

Mantenere la logica sul lato del database è quasi sempre una cosa giusta da fare.

Come hai detto nella tua domanda, la maggior parte delle regole di business coinvolgono una logica abbastanza semplice, ma di solito tratta enormi volumi di dati.

Il motore di database è la cosa giusta per implementare quella logica perché, in primo luogo, mantiene i dati I/O al minimo e, in secondo luogo, il database esegue le trasformazioni dei dati Mosts in modo molto più efficiente.

Qualche tempo fa ho scritto un post molto soggettivo su questo argomento:

nota

Un lato: un UDF non è lo stesso di una stored procedure.

A UDF A è una funzione progettata da callable all'interno di una query, quindi può fare solo un sottoinsieme molto limitato di operazioni possibili.

Si può fare molto di più è una procedura memorizzata.

Aggiornamento:

Nell'esempio hai dato, come cambiare la logica che calcola un "campo derivato", il UDF che calcola il campo è OK.

Ma (nel caso in cui) le prestazioni saranno un problema (e credetemi, questo sarà molto prima che si possa pensare), la trasformazione dei dati con operazioni basate su set potrebbe essere molto più efficiente rispetto all'utilizzo di UDF s.

In questo caso, è possibile creare una vista, una stored procedure o una funzione di valore di tabella restituendo un set di risultati che conterrà una query più efficiente piuttosto che limitarsi all'aggiornamento di UDF s (che sono basati su record) .

Un esempio: la ricerca ha qualcosa come "punteggio user", che si sente di essere soggetti a modifiche e avvolgerlo in un UDF

SELECT user_id, fn_getUserScore(user_id) 
FROM users 

Inizialmente, questo è solo un campo di pianura nella tabella:

CREATE FUNCTION fn_getUserScore(@user_id INT) RETURNS INT 
AS 
BEGIN 
     DECLARE @ret INT 
     SELECT user_score 
     INTO @ret 
     FROM users 
     WHERE user_id = @user_id 
     RETURN @ret 
END 

, allora si decide che calcolarlo utilizzando i dati di altra tabella:

CREATE FUNCTION fn_getUserScore(@user_id INT) RETURNS INT 
AS 
BEGIN 
     DECLARE @ret INT 
     SELECT SUM(vote) 
     INTO @ret 
     FROM user_votes 
     WHERE user_id = @user_id 
     RETURN @ret 
END 

Questo condannerà il motore all'utilizzo dell'algoritmo meno efficiente NESTED LOOPS in entrambi i casi.

Ma se si è creato una vista e riscritto le query sottostanti come questo:

SELECT user_id, user_score 
FROM users 

SELECT user_id, SUM(vote) AS user_score 
FROM users u 
LEFT JOIN 
     user_votes uv 
ON uv.user_id = u.user_id 

, questo darebbe il motore spazio molto più ampio per l'ottimizzazione, pur mantenendo la struttura di risultati e separare la logica dalla presentazione.

+1

+1 per mantenere la logica sul lato db (anche se molti sarebbero fortemente in disaccordo) – davek

+0

Non so se sto cercando! l'efficienza più che la semplice separazione di queste regole da qualunque sia la scelta per implementare i report - Voglio solo che le persone siano in grado di guardare i dati e di essere come "ah ah, c'è il campo derivato X, dove voglio filtrare per 'N "" o qualcosa del genere :) Se la logica cambia per il campo derivato X in base a qualche feedback, basta aggiornare un UDF o due e aggiornare quel campo. Questa è la mia visione, comunque;) – chucknelson

+0

'@ chucknelson': Vorrei avere persone che sarebbero in grado di vedere un "campo derivata" nei dati come i miei clienti :) – Quassnoi

Problemi correlati