Wrning per select tra due date

giovedì 12 luglio 2007 - 12.28

bluland Profilo | Guru

salve,
ho due calendari per effettuare una select come da oggetto,la paura e' che se il range e' troppo grande mi si potrebbe impallare il server, come regolate questo problema??

saluti
--------------------
Vincenzo PESANTE
System Engineer

alx_81 Profilo | Guru

>salve,
Ciao!

>ho due calendari per effettuare una select come da oggetto,la
>paura e' che se il range e' troppo grande mi si potrebbe impallare
>il server, come regolate questo problema??
Impallare il server? in che senso ? CPU? Disco? cosa?

Se hai modellato bene il tuo database, l'impegno del server è minimo se i dati non sono tantissimi..
Sel la mole dei dati su cui lavorare è molto ampia, se le query non sono ottimizzate, se in generale il tuning della macchina/database non è stato effettuato al meglio, il problema è inevitabile .
Il miglior modo per ottenere i dati in maniera veloce è costruire su un server "adatto" un database modellato per bene, con tanto di indici al posto giusto e query che li sfruttano appieno.. Se anche dopo tutte queste operazioni ottieni i dati in troppo tempo dovrai limitare il range massimo, negando la possibilità di ricercare a chi prova a fare ricerche con date troppo distanti.

Il tuo db è un sql server? sei sicuro che tutti gli oggetti siano ottimizzati, eventualmente indicizzati e quant'altro? sei sicuro che le query siano create al meglio per la base dati?
Devi porti un po' tutte le domande del caso e seguire il più possibile alcune delle best practices di base..
Di più non so che dirti..
Alx81 =)

http://blogs.dotnethell.it/suxstellino

bluland Profilo | Guru

grazie per la risposta ale,

in realta' il database e' costituito da una sola tabella in sql server 2000, ad oggi ci sono circa 50000 record, ma pensavo ad una situazione futura in cui magari ci saranno 200 o 300 mila record, se si dovesse effettuare una ricerca tra date che li copre tutti ovviamente le prestazioni diminuirebbero magari terrebbero occupato il server per un po' di tempo, per questo chiedevo un consiglio come evitare questo problema, avevo pensato che magari era possibile mettere un contatore al momento che si lancia la query, nel caso che non ritorna risultati entro un certo tempo magari interrompere l'esecuzione, che ne pensi?

saluti
--------------------
Vincenzo PESANTE
System Engineer

alx_81 Profilo | Guru

>grazie per la risposta ale,
di nulla sei il primo che mi chiama per nome da un po' di tempo..
>
>in realta' il database e' costituito da una sola tabella in sql
>server 2000, ad oggi ci sono circa 50000 record, ma pensavo ad
>una situazione futura in cui magari ci saranno 200 o 300 mila
>record, se si dovesse effettuare una ricerca tra date che li
>copre tutti ovviamente le prestazioni diminuirebbero magari terrebbero
>occupato il server per un po' di tempo, per questo chiedevo un
>consiglio come evitare questo problema, avevo pensato che magari
>era possibile mettere un contatore al momento che si lancia la
>query, nel caso che non ritorna risultati entro un certo tempo
>magari interrompere l'esecuzione, che ne pensi?
Penso che 500000 righe non sono tantissime ..
che ne dici di postare lo script della tabella con gli indici.. a mio avviso, ottimizzandola bene non dovresti avere problemi..
più che altro, se devi visualizzare molti record, utilizza una paginazione.. perchè a volte la query ci mette "poco" ma poi la pagina web perde tempo nella renderizzazione dei contenuti..
gestisci una paginazione, e se hai sql server 2005, ti vengono forniti strumenti per farla con pochissimo sforzo..
per ora posta la tabella
vediamo come possiamo migliorare (se ce n'è bisogno) ..
poi pensiamo al web.. ok?
ciao!

Alx81 =)

http://blogs.dotnethell.it/suxstellino

bluland Profilo | Guru

>>grazie per la risposta ale,
>di nulla sei il primo che mi chiama per nome da un po' di
>tempo..
>>

>Penso che 500000 righe non sono tantissime ..
>che ne dici di postare lo script della tabella con gli indici..
>a mio avviso, ottimizzandola bene non dovresti avere problemi..
>più che altro, se devi visualizzare molti record, utilizza una
>paginazione.. perchè a volte la query ci mette "poco" ma poi
>la pagina web perde tempo nella renderizzazione dei contenuti..
>gestisci una paginazione, e se hai sql server 2005, ti vengono
>forniti strumenti per farla con pochissimo sforzo..
>per ora posta la tabella
>vediamo come possiamo migliorare (se ce n'è bisogno) ..
>poi pensiamo al web.. ok?
>ciao!

ecco lo script della tabella

CREATE TABLE [OSM_Ord] ( [id] [decimal](18, 0) IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL , [SpA_Order] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL , [Sud_Order] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL , [NRPL-ShopOrder] [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL , [T&CC_Date] [datetime] NULL , [Prepack_IN_Date] [datetime] NULL , [Shipping_Date] [datetime] NULL , [Acceptance_Date] [datetime] NULL , [Allocation_Date] [datetime] NULL , CONSTRAINT [PK_ORD_Web] PRIMARY KEY CLUSTERED ( [id] ) ON [PRIMARY] ) ON [PRIMARY] GO

credo che sia abbastanza semplice non so cosa si potrebbe migliorare, ripeto il db e' sql 2000,
la mia paura e' se venisse fatta una query del tipo:
SELECT * FROM [OSM_Ord] WHERE [T&CC_Date] BETWEEN '' AND ' ' che va a prendere tutti i record il che e' come fare una
SELECT * FROM [OSM_Ord].

CIao




--------------------
Vincenzo PESANTE
System Engineer

alx_81 Profilo | Guru

>credo che sia abbastanza semplice non so cosa si potrebbe migliorare,
>ripeto il db e' sql 2000,
e gli indici? non li hai sacriptati o non ci sono?

>la mia paura e' se venisse fatta una query del tipo:
>SELECT * FROM [OSM_Ord] WHERE [T&CC_Date] BETWEEN '' AND ' '
>che va a prendere tutti i record il che e' come fare una
>SELECT * FROM [OSM_Ord].
dipende dagli indici..

>
>CIao
ciao!
Alx81 =)

http://blogs.dotnethell.it/suxstellino

bluland Profilo | Guru

non ci sono !!
questa e' la tabella, tu come la indicizzeresti?
--------------------
Vincenzo PESANTE
System Engineer

alx_81 Profilo | Guru

>non ci sono !!
beh.. allora andrà peggio sicuramente

>questa e' la tabella, tu come la indicizzeresti?
Innanzitutto riscriverei la query senza il between per comprendere tutti i valori (ho cambiato i nomi delle colonne NRPL-ShopOrder
e T&CC_Date, che non seguono gli standard):

SELECT id , SpA_Order , Sud_Order , NRPL_ShopOrder , TCC_Date , Prepack_IN_Date , Shipping_Date , Acceptance_Date , Allocation_Date FROM OSM_Ord WHERE TCC_Date >= @DataInizio AND TCC_Date <= @DataFine

poi, visto che il filtro è solo sulla data e che si tratta di una range search, metterei la PRIMARY KEY NONCLUSTERED e farei un indice CLUSTERED sul campo del range (TCC_Date). Successivamente controllerei se effettivamente mi servono tutti i campi della select. In caso negativo, indicherei solo quelli che mi servono.. Altra cosa da fare, se possibile, è dimensionare correttamente i tipi di dato, indicando il tipo più piccolo che soddisfa le esigenze del campo. I datetime, ad esempio, se non ti servono date inferiori al 1900 e se non ti serve la precisione dei secondi, sostituiscili con smalldatetime.. Ed infine, la normalizzazione.. se ci sono campi ridondanti che puoi portare in forma di relazione, fallo.. altrimenti la query impiegherà sempre molto tempo.

Eccoti un paio di esempi, impostando i flag STATISTICS IO e TIME ad ON (includono statistiche sull'input output e sui tempi di esecuzione):

caso 1: CLUSTERED SULLA CHIAVE PRIMARIA.

a) con filtro where che coinvolge tutta la tabella, 500000 righe:

Table 'OSM_Ord'. Scan count 1, logical reads 20938, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 610 ms, elapsed time = 16166 ms.

Quindi 20938 letture in 16 secondi. Il piano di esecuzione fa Clustered Index Scan.

b) con filtro ristretto, 300000 righe:

Table 'OSM_Ord'. Scan count 1, logical reads 20938, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 594 ms, elapsed time = 6224 ms.

Stesso numero di letture ma minor tempo, 6 secondi e stesso piano.



caso 2: CLUSTERED SUL CAMPO TCC_Date.

a) con filtro where che coinvolge tutta la tabella, 500000 righe:

Table 'OSM_Ord'. Scan count 1, logical reads 20938, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 594 ms, elapsed time = 15870 ms.

Quindi 20938 letture in 15 secondi. Il piano di esecuzione fa Clustered Index Seek.

b) con filtro ristretto (e qui ci risparmia sull'IO), 300000 righe:

Table 'OSM_Ord'. Scan count 1, logical reads 13144, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 484 ms, elapsed time = 5720 ms.

Numero di IO quasi dimezzato, piano con Clustered Index Seek.

Dopo aver fatto questi test possiamo concludere che se vai a filtrare per range più ristretti dell'intera tabella ti conviene fare il clustered sulla data, poichè nel primo caso, qualunque sia il range di date su cui ricerchiamo, le letture sono le medesime. Nel secondo invece l'IO si riduce notevolmente, fino a quasi dimezzarsi. Escludo infine la possibilità di lasciare la chiave come la indichi tu e mettere l'indice nonclustered sulla data, poichè i risultati sono gli stessi del primo caso. Nella tua problematica, con 500000 righe di prova, SQL preferisce infatti fare clustered index scan per ogni filtro, quindi il caso 1. Io utilizzerei il caso due, poichè non è detto che la tua select faccia sempre richiesta a tutti i record e quindi risparmierei sull'io.. Considera che se le due date sono vicine, i cicli di lettura si riducono drasticamente!! e quindi anche i tempi.

Qui di seguito la tabella "ridimensionata" a mio piacimento.. proprio a titolo di esempio, con tipi dato più piccoli:

CREATE TABLE OSM_Ord ( [id] decimal(18, 0) IDENTITY (1, 1) NOT NULL, SpA_Order varchar(30), Sud_Order varchar(30), NRPL_ShopOrder varchar (30), TCC_Date smalldatetime NULL, Prepack_IN_Date smalldatetime NULL, Shipping_Date smalldatetime NULL, Acceptance_Date smalldatetime NULL, Allocation_Date smalldatetime NULL, CONSTRAINT PK_ORD_Web PRIMARY KEY NONCLUSTERED ( [id] ) ) GO CREATE CLUSTERED INDEX IX_OSM_Ord_Data ON OSM_Ord ( TCC_Date )

Ecco i risultati eseguendo le stesse query dei casi precedenti (filtro su tutta la tabella, filtro ristretto)

a) filtro esteso, solite 500000 righe:

Table 'OSM_Ord'. Scan count 1, logical reads 8988, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 438 ms, elapsed time = 10820 ms.

Letture e tempi ridotti drasticamente per la select con filtro esteso , piano Clustered Index Seek.

b) filtro ridotto, solite 300000 righe:

Table 'OSM_Ord'. Scan count 1, logical reads 5395, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 234 ms, elapsed time = 5411 ms.

Letture e tempi ridotti drasticamente per la select anche con filtro ridotto, piano Clustered Index Seek.

Ho allegato questo esempio, perchè è importante farti capire che il dimensionamento, gli indici, i tipi di indici, la modellazione delle tabelle sono tutte cose fondamentali da configurare per essere veloci. Meglio analizzi questa parte, più risultati positivi avrai. Cambiando non di molto alcuni campi, si ottiene addirittura un numero di letture di 3 volte più piccolo per i filtri estesi.. e più il filtro è mirato più le letture calano..

Ora, prendi pure la tua decisione , spero di essere stato sufficientemente chiaro!
ciao!
Alx81 =)

http://blogs.dotnethell.it/suxstellino

bluland Profilo | Guru

grazie degli esempi!!

avrei alcune domande:

1. Che differenza c'e tra indicare una Pk clustered o non clustered?

2. calcolando che in questa tabella saranno fatti circa 500/600 inserimenti al giorno, di non converebbe definire degli indici giusto?

3. come si usa l'indice nell'esempio che ha riportato?

4. perche non usare il BETWEEN?

saluti
--------------------
Vincenzo PESANTE
System Engineer

alx_81 Profilo | Guru

>grazie degli esempi!!
>
>avrei alcune domande:
>
>1. Che differenza c'e tra indicare una Pk clustered o non clustered?
Indipendentemente dalla pk.. clustered è un indice che ordina fisicamente la tabella. Un indice clustered alla fine, per semplificare, è una tabella ordinata fisicamente per i campi definiti nell'indice.
Non clustered (sempre semplificando al massimo) è una struttura che punta ai record, in più rispetto alla tabella stessa, come un indice analitico ti dice la pagina su cui andare a cercare la parola..
però ti consiglio di documentarti bene, perchè ci sarebbe da perdere una settimana a parlare di indici..
>
>2. calcolando che in questa tabella saranno fatti circa 500/600 inserimenti al giorno, di non converebbe definire degli indici giusto?
Beh.. no.. conviene invece.. perchè oltre che inserirli poi dovrai pur leggerli no?
Magari cambia il loro FILLFACTOR, ovvero il fattore di riempimento di ogni nodo dell'albero dell'indice.. in questo modo puoi decidere di lasciare spazio per gli inserimenti, tenendo sempre una ricerca veloce ed ottimizzata.
leggi qui (cercando FILLFACTOR)
http://msdn2.microsoft.com/it-it/library/ms188783.aspx
>
>3. come si usa l'indice nell'esempio che ha riportato?
Come?? cosa intendi? è il motore di sql server che lo usa.. in base alle query che scrivi tu e alle statistiche che si è creato l'engine internamente..
>
>4. perche non usare il BETWEEN?
perchè se non usato correttamente il between esclude gli orari dell'estremo destro, arriva fino alla mezzanotte dell'estremo destro.
Se vuoi usare between aggiungi alla data l'orario massimo di destra (ad esempio 23:50.59....).
>
>saluti
>--------------------
>Vincenzo PESANTE
>System Engineer

Alx81 =)

http://blogs.dotnethell.it/suxstellino

bluland Profilo | Guru

bene mi e' chiaro grazie

per la risp 4:

si infatti alla fine delle date mi tocca aggiungere gli orari.


grazie alla prossima
--------------------
Vincenzo PESANTE
System Engineer
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5