2008-09-11 6 views
3

Ich habe eine Tabelle in SQL Server, die ich von einem Legacy-System geerbt habe, das noch in Produktion ist, die nach dem folgenden Code strukturiert ist. Ich habe einen SP erstellt, um die Tabelle abzufragen, wie im Code unterhalb der Anweisung create beschrieben. Mein Problem ist, dass sporadisch Aufrufe von .NET zu diesem SP sowohl über die Enterprise Library 4 als auch über ein DataReader-Objekt langsam sind. Der SP wird über eine Schleifenstruktur in der Datenschicht aufgerufen, die die Parameter angibt, die zum Zweck des Auffüllens von Benutzerobjekten in den SP gelangen. Es ist auch wichtig zu erwähnen, dass ein langsamer Aufruf nicht bei jedem Durchlauf der Schleifenstruktur stattfinden wird. Es wird in der Regel für die meisten von einem Tag oder mehr in Ordnung sein, und dann zu präsentieren beginnen, was es extrem schwierig macht zu debuggen.Sporadisch langsame Aufrufe von .NET-Anwendung an SQL Server

Die fragliche Tabelle enthält etwa 5 Millionen Zeilen. Zum Beispiel dauern die langsamen Anrufe 10 Sekunden, während die schnellen Anrufe durchschnittlich 0 bis 10 Millisekunden benötigen. Ich habe während der langsamen Anrufe nach blockierenden/blockierenden Transaktionen gesucht, keine wurden gefunden. Ich habe einige benutzerdefinierte Leistungsindikatoren in der Datenschicht erstellt, um die Anrufzeiten zu überwachen. Wenn Leistung schlecht ist, ist es wirklich schlecht für diesen einen Anruf. Aber wenn es gut ist, ist es wirklich gut. Ich konnte das Problem auf einigen verschiedenen Entwicklungsmaschinen reproduzieren, aber nicht auf unseren Entwicklungs- und Staging-Datenbankservern, die natürlich robustere Hardware haben. Im Allgemeinen wird das Problem durch einen Neustart der SQL Server-Dienste gelöst, aber nicht immer. Es gibt Indizes in der Tabelle für die Felder, die ich abfrage, aber es gibt mehr Indizes als ich möchte. Ich zögere jedoch, irgendwelche oder Spielzeug mit den Indizes aufgrund der Auswirkungen auf das Altsystem zu entfernen. Hat jemand schon einmal ein solches Problem erlebt oder haben Sie eine Empfehlung, Abhilfe zu schaffen?

CREATE TABLE [dbo].[product_performance_quarterly](
    [performance_id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL, 
    [product_id] [int] NULL, 
    [month] [int] NULL, 
    [year] [int] NULL, 
    [performance] [decimal](18, 6) NULL, 
    [gross_or_net] [char](15) NULL, 
    [vehicle_type] [char](30) NULL, 
    [quarterly_or_monthly] [char](1) NULL, 
    [stamp] [datetime] NULL CONSTRAINT [DF_product_performance_quarterly_stamp] DEFAULT (getdate()), 
    [eA_loaded] [nchar](10) NULL, 
    [vehicle_type_id] [int] NULL, 
    [yearmonth] [char](6) NULL, 
    [gross_or_net_id] [tinyint] NULL, 
CONSTRAINT [PK_product_performance_quarterly_4_19_04] PRIMARY KEY CLUSTERED 
(
    [performance_id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY] 
) ON [PRIMARY] 

GO 
SET ANSI_PADDING OFF 
GO 
ALTER TABLE [dbo].[product_performance_quarterly] WITH NOCHECK ADD CONSTRAINT [FK_product_performance_quarterlyProduct_id] FOREIGN KEY([product_id]) 
REFERENCES [dbo].[products] ([product_id]) 
GO 
ALTER TABLE [dbo].[product_performance_quarterly] CHECK CONSTRAINT [FK_product_performance_quarterlyProduct_id] 

CREATE PROCEDURE [eA.Analytics.Calculations].[USP.GetCalculationData] 
(
    @PRODUCTID INT,      --products.product_id 
    @BEGINYEAR INT,      --year to begin retrieving performance data 
    @BEGINMONTH INT,     --month to begin retrieving performance data 
    @ENDYEAR INT,      --year to end retrieving performance data 
    @ENDMONTH INT,      --month to end retrieving performance data 
    @QUARTERLYORMONTHLY VARCHAR(1),  --do you want quarterly or monthly data? 
    @VEHICLETYPEID INT,     --what product vehicle type are you looking for? 
    @GROSSORNETID INT     --are your looking gross of fees data or net of fees data? 
) 
AS 
BEGIN 

    SET NOCOUNT ON 

    DECLARE @STARTDATE VARCHAR(6), 
      @ENDDATE VARCHAR(6), 
      @vBEGINMONTH VARCHAR(2), 
      @vENDMONTH VARCHAR(2) 

IF LEN(@BEGINMONTH) = 1 
    SET @vBEGINMONTH = '0' + CAST(@BEGINMONTH AS VARCHAR(1)) 
ELSE 
    SET @vBEGINMONTH = @BEGINMONTH 

IF LEN(@ENDMONTH) = 1 
    SET @vENDMONTH = '0' + CAST(@ENDMONTH AS VARCHAR(1)) 
ELSE 
    SET @vENDMONTH = @ENDMONTH 

SET @STARTDATE = CAST(@BEGINYEAR AS VARCHAR(4)) + @vBEGINMONTH 
SET @ENDDATE = CAST(@ENDYEAR AS VARCHAR(4)) + @vENDMONTH 

--because null values for gross_or_net_id and vehicle_type_id are represented in 
--multiple ways (true null, empty string, or 0) in the PPQ table, need to account for all possible variations if 
--a -1 is passed in from the .NET code, which represents an enumerated value that 
--indicates that the value(s) should be true null. 

IF @VEHICLETYPEID = '-1' AND @GROSSORNETID = '-1' 
    SELECT 
     PPQ.YEARMONTH, PPQ.PERFORMANCE 
    FROM PRODUCT_PERFORMANCE_QUARTERLY PPQ 
     WITH (NOLOCK) 
    WHERE 
     (PPQ.PRODUCT_ID = @PRODUCTID) 
     AND (PPQ.YEARMONTH BETWEEN @STARTDATE AND @ENDDATE) 
     AND (PPQ.QUARTERLY_OR_MONTHLY = @QUARTERLYORMONTHLY) 
     AND (PPQ.VEHICLE_TYPE_ID IS NULL OR PPQ.VEHICLE_TYPE_ID = '0' OR PPQ.VEHICLE_TYPE_ID = '') 
     AND (PPQ.GROSS_OR_NET_ID IS NULL OR PPQ.GROSS_OR_NET_ID = '0' OR PPQ.GROSS_OR_NET_ID = '') 
    ORDER BY PPQ.YEARMONTH ASC 

IF @VEHICLETYPEID <> '-1' AND @GROSSORNETID <> '-1' 
    SELECT 
     PPQ.YEARMONTH, PPQ.PERFORMANCE 
    FROM PRODUCT_PERFORMANCE_QUARTERLY PPQ 
     WITH (NOLOCK) 
    WHERE 
     (PPQ.PRODUCT_ID = @PRODUCTID) 
     AND (PPQ.YEARMONTH BETWEEN @STARTDATE AND @ENDDATE) 
     AND (PPQ.QUARTERLY_OR_MONTHLY = @QUARTERLYORMONTHLY) 
     AND (PPQ.VEHICLE_TYPE_ID = @VEHICLETYPEID) 
     AND (PPQ.GROSS_OR_NET_ID = @GROSSORNETID) 
    ORDER BY PPQ.YEARMONTH ASC 

IF @VEHICLETYPEID = '-1' AND @GROSSORNETID <> '-1' 
    SELECT 
     PPQ.YEARMONTH, PPQ.PERFORMANCE 
    FROM PRODUCT_PERFORMANCE_QUARTERLY PPQ 
     WITH (NOLOCK) 
    WHERE 
     (PPQ.PRODUCT_ID = @PRODUCTID) 
     AND (PPQ.YEARMONTH BETWEEN @STARTDATE AND @ENDDATE) 
     AND (PPQ.QUARTERLY_OR_MONTHLY = @QUARTERLYORMONTHLY) 
     AND (PPQ.VEHICLE_TYPE_ID IS NULL OR PPQ.VEHICLE_TYPE_ID = '0' OR PPQ.VEHICLE_TYPE_ID = '') 
     AND (PPQ.GROSS_OR_NET_ID = @GROSSORNETID) 
    ORDER BY PPQ.YEARMONTH ASC 

IF @VEHICLETYPEID <> '-1' AND @GROSSORNETID = '-1' 
    SELECT 
     PPQ.YEARMONTH, PPQ.PERFORMANCE 
    FROM PRODUCT_PERFORMANCE_QUARTERLY PPQ 
     WITH (NOLOCK) 
    WHERE 
     (PPQ.PRODUCT_ID = @PRODUCTID) 
     AND (PPQ.YEARMONTH BETWEEN @STARTDATE AND @ENDDATE) 
     AND (PPQ.QUARTERLY_OR_MONTHLY = @QUARTERLYORMONTHLY) 
     AND (PPQ.VEHICLE_TYPE_ID = @VEHICLETYPEID) 
     AND (PPQ.GROSS_OR_NET_ID IS NULL OR PPQ.GROSS_OR_NET_ID = '0' OR PPQ.GROSS_OR_NET_ID = '') 
    ORDER BY PPQ.YEARMONTH ASC 

END 

Antwort

0

Klingt wie eine andere Abfrage im Hintergrund ausgeführt wird, der die Tabelle und Ihre unschuldige Abfrage wartet gesperrt hat, ist einfach für sie

1

zu beenden Ich habe dies mit Indizes geschehen gesehen, die veraltet waren. Es könnte auch ein Parameter-Sniffing-Problem sein, bei dem ein anderer Abfrageplan für verschiedene Parameter verwendet wird, die in die gespeicherte Prozedur eingehen.

Sie sollten die Parameter der langsamen Aufrufe erfassen und sehen, ob sie jedes Mal dieselben sind, wenn sie langsam ausgeführt werden.

Sie können auch versuchen, den Tuning-Assistenten auszuführen und prüfen, ob er Indizes empfiehlt.

Sie sollten sich keine Sorgen über zu viele Indizes machen, bis Sie nachweisen können, dass Aktualisierungen und Einfügungen zu langsam sind (Zeit zum Ändern des Index plus Sperren/Konflikte) oder Ihnen der Speicherplatz dafür knapp wird Sie.

0

Ein seltsames, Rand Fall, aber ich traf es vor kurzem.

Wenn die Abfragen in der Anwendung länger ausgeführt werden als bei der Ausführung in Management Studio, sollten Sie überprüfen, ob Arithabort deaktiviert ist. Die von Management Studio verwendeten Verbindungsparameter unterscheiden sich von denen, die von .NET verwendet werden.

+0

Ich habe das auch gesehen, aber ich mache mir Sorgen, dass das Ausschalten das Problem einfach umkehrt (die schnellen Abfragen laufen jetzt langsam). Der einzige Grund, warum ich weiß, dass dies Auswirkungen auf Dinge hat, hängt mit Parameter-Sniffing zusammen, wo ein anderer Plan gewählt wird. –

+0

Ich habe dieses Problem nicht festgestellt. Wenn ich es ausschalte, wird es gleichgesetzt mit dem, in dem SMS es ausführt. So habe ich das Problem gefunden. – Josef

0

Es scheint, als wäre es eines von zwei Dingen - entweder sind die Parameter der langsamen Aufrufe anders als bei den schnellen Aufrufen, und sie sind nicht in der Lage, die Indizes zu verwenden, oder es gibt eine Art von Sperrung Streit, der dich aufhält. Sie sagen, Sie haben geprüft, ob Sperren gesperrt sind, während ein bestimmter Prozess angehalten wurde, und Sie haben keine gesehen - dies würde darauf hindeuten, dass es sich um den ersten handelt. Sind Sie jedoch sicher, dass Ihr Staging-Server (auf dem Sie diesen Fehler nicht reproduzieren können) und die Entwicklungsserver (auf denen Sie diesen Fehler reproduzieren können) dieselbe Datenbankkonfiguration haben? Zum Beispiel ist vielleicht "READ COMMITTED SNAPSHOT" in der Produktion aktiviert, aber nicht in der Entwicklung, was dazu führen würde, dass Probleme beim Lesen von Konflikten in der Produktion verschwinden würden.Wenn es sich um einen Unterschied in den Parametern handelt, würde ich vorschlagen, SQL Profiler zu verwenden, um die Transaktionen zu überwachen und einige - einige langsame und einige schnellere - zu erfassen und dann in einem Management Studio-Fenster die Variablen in diesem SP zu ersetzen oben mit den Parameterwerten und erhalten dann einen Ausführungsplan durch Drücken von "Control-L". Dadurch erfahren Sie genau, wie SQL Server Ihre Abfrage verarbeitet, und Sie können den Ausführungsplan für verschiedene Parameter vergleichen, um festzustellen, ob ein Unterschied zu einem Satz besteht, und von dort aus arbeiten, um ihn zu optimieren.

Viel Glück!