SQL-Server kein index in der gespeicherten Prozedur

Ich habe nicht dieses Problem gelöst, indem Sie die gespeicherte Prozedur, doch wir haben beschlossen, zu übertreffen, die SP und führen nur die plain ol' SQL

Bitte sehen Sie sich die erweiterte Tabelle Schema unten

Edit 2: Aktualisiert den index (nicht für die Verwendung der actieGroep mehr)

NB. SQL Server 2005 Enterprise 9.00.4035.00

NB2. Scheint im Zusammenhang mit http://www.sqlservercentral.com/Forums/Topic781451-338-1.aspx

Habe ich zwei Indizes auf eine Tabelle:

  • Ein clustered PK-index auf statistiekId
  • Einen nicht-gruppierten index auf foreignId

Und ich habe das folgende Stück code:

DECLARE @fid BIGINT
SET @fid = 873926

SELECT foreignId
FROM STAT_Statistieken
WHERE foreignId = @fid

Diese führt genau so, wie es sollte; es verweist auf den richtigen index, und alle es tut, ist das Scannen der index.

Nun bin ich durch das erstellen einer gespeicherten Prozedur:

ALTER PROCEDURE MyProcedure (@fid BIGINT)
AS BEGIN
    SELECT foreignId
    FROM STAT_Statistieken
    WHERE foreignId = @fid
END

Läuft die Sache:

EXEC MyProcedure @fid = 873926

Nun läuft es ein clustered index scan auf meinem PK-index! Wtf ist da Los?

Also änderte ich die SP zu

SELECT foreignId
FROM STAT_Statistieken
    WITH (INDEX(IX_STAT_Statistieken_2))
WHERE foreignId = @fid

Und jetzt gibt es: Abfrage-Prozessor konnte keinen Abfrage-plan erzeugen, weil die Hinweise in dieser Abfrage. Übermitteln Sie die Abfrage ohne Angabe von hinweisen und ohne SET FORCEPLAN. Während die gleiche Funktion ausgeführt wird, wie sollte es bei der Ausführung dieses direkt.


Extra-info: die vollständige Regelung, die sich reproduzieren können dieses Verhalten (englische Namen im Kommentar)

Tabelle

CREATE TABLE [dbo].[STAT_Statistieken](
    [statistiekId] [bigint] IDENTITY(1,1) NOT NULL,
    [foreignId] [bigint] NOT NULL,
    [datum] [datetime] NOT NULL, --date
    [websiteId] [int] NOT NULL,
    [actieId] [int] NOT NULL, --actionId
    [objectSoortId] [int] NOT NULL, --kindOfObjectId
    [aantal] [bigint] NOT NULL, --count
    [secondaryId] [int] NOT NULL DEFAULT ((0)),
    [dagnummer]  AS (datediff(day,CONVERT([datetime],'2009-01-01 00:00:00.000',(121)),[datum])) PERSISTED, --daynumber
    [actieGroep]  AS (substring(CONVERT([varchar](4),[actieId],0),(1),(1))) PERSISTED,
    CONSTRAINT [STAT_Statistieken_PK] PRIMARY KEY CLUSTERED --actionGroup
    (
        [statistiekId] ASC
    )WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY]

Index

CREATE NONCLUSTERED INDEX [IX_STAT_Statistieken_foreignId_dagnummer_actieId_secondaryId] ON [dbo].[STAT_Statistieken] 
(
    [foreignId] ASC,
    [dagnummer] ASC,
    [actieId] ASC,
    [secondaryId] ASC
)WITH (PAD_INDEX  = ON, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, FILLFACTOR = 80, ONLINE = OFF) ON [PRIMARY]

Ausführung

SET NOCOUNT ON;

    DECLARE @maand INT, @jaar INT, @foreignId BIGINT
    SET @maand = 9
    SET @jaar = 2009
    SET @foreignId = 828319


DECLARE @startDate datetime, @endDate datetime
SET @startDate = DATEADD(month, -1, CONVERT(datetime,CAST(@maand AS varchar(3))+'-01-'+CAST(@jaar AS varchar(5))))
SET @endDate = DATEADD(month, 1, CONVERT(datetime,CAST(@maand AS varchar(3))+'-01-'+CAST(@jaar AS varchar(5))))

DECLARE @firstDayDezeMaand datetime
SET @firstDayDezeMaand = CONVERT(datetime, CAST(@jaar AS VARCHAR(4)) + '/' + CAST(@maand AS VARCHAR(2)) + '/1')

DECLARE @daynumberFirst int
set @daynumberFirst = DATEDIFF(day, '2009/01/01', @firstDayDezeMaand)

DECLARE @startDiff int
SET @startDiff = DATEDIFF(day, '2009/01/01', @startDate)

DECLARE @endDiff int
SET @endDiff = DATEDIFF(day, '2009/01/01', @endDate)

SELECT @foreignId AS foreignId,
    SUM(CASE WHEN dagnummer >= @daynumberFirst THEN (CASE WHEN actieId BETWEEN 100 AND 199 THEN aantal ELSE 0 END) ELSE 0 END) as aantalGevonden, 
    SUM(CASE WHEN dagnummer >= @daynumberFirst THEN (CASE WHEN actieId BETWEEN 200 AND 299 THEN aantal ELSE 0 END) ELSE 0 END) as aantalBekeken, 
    SUM(CASE WHEN dagnummer >= @daynumberFirst THEN (CASE WHEN actieId BETWEEN 300 AND 399 THEN aantal ELSE 0 END) ELSE 0 END) as aantalContact,
    SUM(CASE WHEN dagnummer < @daynumberFirst THEN (CASE WHEN actieId BETWEEN 100 AND 199 THEN aantal ELSE 0 END) ELSE 0 END) as aantalGevondenVorige, 
    SUM(CASE WHEN dagnummer < @daynumberFirst THEN (CASE WHEN actieId BETWEEN 200 AND 299 THEN aantal ELSE 0 END) ELSE 0 END) as aantalBekekenVorige, 
    SUM(CASE WHEN dagnummer < @daynumberFirst THEN (CASE WHEN actieId BETWEEN 300 AND 399 THEN aantal ELSE 0 END) ELSE 0 END) as aantalContactVorige
FROM STAT_Statistieken
WHERE
    dagnummer >= @startDiff
    AND dagnummer < @endDiff
    AND foreignId = @foreignId 
OPTION(OPTIMIZE FOR (@foreignId = 837334, @startDiff = 200, @endDiff = 300))

DBCC Statistik

Name                                                          | Updated               | Rows      | Rows smpl | Steps | Density | Avg. key | String index
IX_STAT_Statistieken_foreignId_dagnummer_actieId_secondaryId    Oct  6 2009  3:46PM 1245058    1245058    92    0,2492834    28    NO

All Density  | Avg. Length | Columns
3,227035E-06    8    foreignId
2,905271E-06    12    foreignId, dagnummer
2,623274E-06    16    foreignId, dagnummer, actieId
2,623205E-06    20    foreignId, dagnummer, actieId, secondaryId
8,031755E-07    28    foreignId, dagnummer, actieId, secondaryId, statistiekId

RANGE HI | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE ROWS
-1         0            2         0                     1
1356       3563         38        1297                  2,747109
8455       14300        29        6761                  2,115072

Und der index wird verwendet, wie gezeigt in der Ausführung plan. Wenn ich wickeln Sie diese in eine Prozedur mit diesem params:

@foreignId bigint,
@maand int, --month
@jaar int --year

Und führen Sie es mit _SP_TEMP @foreignId = 873924, @maand = 9, @jaar = 2009

Macht es einen clustered index scan!

  • Ist der Punkt der sproc, um herauszufinden, ob ein link vorhanden ist der anderen Tabelle, aus STAT_Statistieken, oder wie viele solcher links vorhanden?
  • Nein, das ist nur eine abstrakte version des Problems. Ich will einfach nur einen SELECT auf die Tabelle mit dem index. Die Tabelle enthält nur eine Reihe von bigints
  • was die Laufzeit der Abfrage bei der Verwendung der gruppierten und die normale index?
  • Cluster: 28 Sek. Non-clustered: < 1 Sek.
  • vermutlich ein strittiger Punkt, aber haben Sie auch aktualisieren Sie Ihre Statistiken, defragmentiert Ihre Indizes (vor allem Ihre clustered-Indizes), ... ?
  • Wenn ich imitieren das schema mit den wenigen Informationen, die ich bekommen keine Probleme, es soll, wie erwartet. Die Fragen über den Abfrage-cache / query plan Treffer / parameter sniffing sind alreayd geschrieben, so ist dies nicht zu lösen, können Sie eine weniger abstrakte version und schema, Sie kann gut sein, das Ausschneiden der erforderlichen Informationen, um zu helfen, wenn und abstrahiert es.
  • Hinzugefügt das vollständige schema in der post.
  • Hallo Jan - irgendwelche Neuigkeiten zu diesem Thema? Ich glaube, ich habe herausgefunden, was war das problem verursacht (eine SQL Server-Optimierer-bug mit permanenten berechneten Spalten). Siehe meine Antwort unten. Lassen Sie mich wissen, wenn es funktioniert!
  • Editiert die index
  • Sind -1, 1356 und 8455 die nächsten Werte zu 873924?
  • Und könnten Sie bitte post die XML Pläne generiert durch die Abfrage und die von der gespeicherten Prozedur? Führen Sie einfach SET SHOWPLAN_XML ON GO SELECT … und SET SHOWPLAN_XML ON GO EXECUTE _SP_TEMP …
  • Hallo Jan - danke für die zusätzliche info... sehr nützlich. Ich gerade erneut meine Antwort mit einem zusätzlichen Vorschlag für das, was kann die Ursache sein und wie es zu lösen. Siehe unten. Auch, @Quassnoi Vorschlag zu post eine XML-plan ist ein guter. Wird definitiv helfen uns bei der diagnose Ihres Problems besser.

InformationsquelleAutor Jan Jongboom | 2009-09-30
Schreibe einen Kommentar