2009-10-02 4 views
8

Si sta utilizzando un ORM che sta eseguendo una chiamata da .NET alla stored procedure sp_executesql di SQL Server.Query SQL lenta da codice .NET, ma non in modo interattivo

Quando il proc memorizzato viene chiamato da .NET, viene ricevuta un'eccezione di timeout.

Guardando Profiler, posso vedere che la query richiede davvero molto tempo per essere eseguita.

la query è essenzialmente:

exec sp_executesql N'SELECT DISTINCT 
FROM [OurDatabase].[dbo].[Contract] [LPLA_1]) [LPA_L1] 
LEFT JOIN [OurDatabase].[dbo].[Customer] [LPA_L2] ON [LPA_L2].[Customer_ID]=[LPA_L1].[CustomerId] AND [LPA_L2].[Data]=[LPA_L1].[Data]) 
WHERE ((((([LPA_L1].[DealerId] = @DealerId1)) 
AND ([LPA_L2].[Last_Name] = @LastName2))))',N'@DealerId1 varchar(18),@LastName2 varchar(25)',@DealerId1='1234',@LastName2='SMITH' 

La parte confusa per me è questo: se copio e incollo la query che è timeout in studio di gestione di SQL ed eseguirlo in modo interattivo, esegue bene.

Qualcuno sa perché la stessa query richiederebbe molto più tempo se eseguita tramite codice .NET? (Sono in grado di riprodurlo - la query eseguita dal codice scade costantemente e la query eseguita in modo interattivo funziona in modo coerente.)

Qualsiasi aiuto è apprezzato. Grazie!

+0

Come molte linee di dati stai tornando? Se ci sono migliaia e migliaia di righe, allora potrebbe richiedere del tempo per passare attraverso il filo al computer aspettandosi un risultato. – Miles

+0

La query restituisce molti dati? Esiste un invio di dati tra server e client coinvolti nel caso del programma che non si verifica in modalità interattiva? – quosoo

+0

Tre nel nostro test case. Inoltre, DealerID e Last_Name hanno indici. –

risposta

0

Sono dealerId o Lastname nvarchar (digitati in modo diverso rispetto ai parametri varchar)?

Ciò può causare la conversione di interi indici. Se trovi che sia così, lascia un commento e ti spiegherò in maggior dettaglio.

+0

No, sono entrambi varcar nel database, sfortunatamente. –

4

Una cosa che ho visto poche volte è se si ha una mancata corrispondenza tra i tipi nvarchar e varchar per un parametro di query in un campo indicizzato. Questo può accadere se si utilizza varchar nel proprio database e non si imposta esplicitamente il tipo di parametro in .Net, che assumerà per impostazione predefinita nvarchar.

In questo caso, Sql Server sceglie l'opzione più corretta anziché l'opzione con prestazioni migliori. Piuttosto che convertire il tuo parametro in varchar, che sarebbe una conversione restringente che potrebbe potenzialmente perdere informazioni, il database sarà costretto a convertire ogni valore per quella colonna nella tabella in un nvarchar (che è garantito per avere successo senza perdita di informazioni) . Non solo è lento, ma il server Sql non sarà più in grado di utilizzare l'indice. Inutile dire che la query richiederà molto più tempo per essere eseguita.

+0

Perché è importante che la query venga eseguita da .NET anziché da SQL Mgmt Studio? –

+0

Hai letto il mio post? Quando crei parametri per il tuo oggetto sqlcommand in .Net (anche se quella parte è nascosta da un orm) e non dici esplicitamente quali sono i tipi di quei parametri, .Net sceglierà per te e potrebbe scegliere di sbagliare. Il risultato è che non è esattamente la stessa query. –

+0

Sì, ma AlexWalker è in esecuzione in SQL Mgmt Studio la query tratta dal profiler ==> è esattamente la stessa query che verrà eseguita alla fine di SQL Server indipendentemente dal mittente (.NET o Mgmt. Studio). A meno che la connessione non sia configurata in modo diverso ... Ho la sensazione che la connessione sia ciò che fa la differenza. –

1

Ho lo stesso problema, una procedura eseguita da .net che impiega troppo tempo (e non restituisce molte righe). Invio una stringa a sql: "execute stored_procedure @ parameter1 = value1" e lo copio ed eseguo su sql management studio, ma lì tutto gira bene. Il motivo di questo caso è che nella mia query aggiungo o rimuovo un LETTER da un valore di parametro per causarlo. Sono molto confuso.

Per informazioni, sto usando l'indice di testo completo e le tabelle temporanee per il paging, ma come ho detto, lo SAME QUERY (e sono sicuro) funziona perfettamente in SQL Management Studio.

1

Appena avuto lo stesso problema.

Gli indici di ricostruzione hanno risolto il problema.

Forse il problema sta nel tipo di parametri che sono nvarchar vs index che si trova su una colonna varchar ...?

1

Penso che sia perché sp_executelsql ha lo scopo di riutilizzare i piani di query compilati, in modo che non riaggiudica i parametri quando la stessa query lo colpisce ancora, così finisce con l'usare un piano che potrebbe essere molto lento (ti spieghi perché un piano di query più lento) con i valori dei parametri correnti.sembra che sp_executesql usi un metodo diverso per la scelta degli indici e apparentemente sia un metodo rotto rispetto a una query di testo normale.

Ciò che differisce è che l'aggiornamento di tabella per "Società (una tabella)" in uno sp_executesql viene alimentato tramite una catena di cicli nidificati mentre la query di testo viene alimentata tramite una catena di corrispondenze hash. La costruzione delle viste appare identica tra le due versioni (che mi aspetterei). Sfortunatamente, il resto è molto complesso e sembra che stiano facendo cose radicalmente diverse nel mezzo; anche tirando un piano di esecuzione "effettivo" non vengono forniti i tempi di esecuzione effettivi per i vari componenti secondari della query. Davvero, non riesco a vedere alcuna ragione per sp_executesql da scegliendo qualcosa di diverso, ma si costruisce in modo affidabile un piano molto più lento.

Lo sniffing dei parametri è una soluzione a questo, quindi è necessario rinominare i nomi dei parametri oppure è possibile scambiare i nomi delle colonne nella clausola where che causa sp_executesql per ricreare un piano di query invece di utilizzare un vecchio piano lento, ovviamente questo è non è la soluzione ma non memorizzerà un piano più lento per così tanto tempo.

Saluti.

+0

Grazie, sembra vero –

1

Ecco quello che ho trovato. Ho un proc memorizzato molto complesso che conta sempre informazioni e mette i dati in un 8 colonna della matrice 17 di fila, come viene chiamato/gestito da Crystal Reports ogni mese. Il database di prod era su un server veloce pazzo di 96 GB! Di recente è stato ridimensionato a una macchina virtuale da 32 GB. Sebbene ridimensionato, ha reso l'app più lenta in molti modi, fino a quando non sono stati aggiunti alcuni indici.

Poi, il periodo del mese è venuto a eseguire questa matrice rapporto mensile 17 di fila ... e come si può immaginare, è scaduta!

La chiamata proc era abbastanza semplice - 3 parametri. Una data di inizio, una data di fine e un distretto da filtrare - null uguale a TUTTO. Le 2 date sono state trasferite da Crystal Reports come carattere e questi parametri PROC memorizzati sono stati poi utilizzati in tutto il luogo durante questo pazzo proc memorizzato.

Ciascuna delle 17 righe - utilizza fondamentalmente le istruzioni WITH e i join pazzeschi per trovare righe di dati prima di contare/pivoting nei risultati ... cosa NON importante in questo articolo.

Così qui è semplificato ....

CREATE PROCEDURE [dbo].[prcMonthlyStats] 
@bDate   datetime 
,@eDate   datetime 
,@districtStr varchar(120) 
AS 
BEGIN 
SET NOCOUNT ON; 

...

--the @bDate and @eDate params were DIRECTLY used throughout the 2000 lines of SQL, 
--to filter data inside and out of WITH statements and various other selects! 
-- 
--TIMES OUT! 

...

CREATE PROCEDURE [dbo].[prcMonthlyStats] 
@bDateStr  datetime 
,@eDateStr  datetime 
,@districtStr varchar(120) 
AS 
BEGIN 
SET NOCOUNT ON; 

--FIX! Declare 2 date time variables and simply assign the 2 date time parameters to them. 
DECLARE @bDate  datetime 
DECLARE @eDate  datetime 
DECLARE @district varchar(120) 

--SET THE VARIABLES FROM THE PARAMETERS PASSED IN! 
SET @bDate = @bDateStr 
SET @eDate = @eDateStr 
SET @district = @districtStr 
..... 

--PRESTO! The optimizer could once again use indexes as it should. 

Quindi morale della storia è - l'ottimizzatore era in grado di fare la sua cosa usando i datet DICHIARATI.