Eine Abfrage wird schnell ausgeführt:
DECLARE @SessionGUID uniqueidentifier
SET @SessionGUID = 'BCBA333C-B6A1-4155-9833-C495F22EA908'
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
Teilbaumkosten: 0,502
Das Einfügen derselben SQL in eine gespeicherte Prozedur wird jedoch langsam und mit einem völlig anderen Ausführungsplan ausgeführt
CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
EXECUTE ViewOpener @SessionGUID
Teilbaumkosten: 19.2
Ich bin gelaufen
sp_recompile ViewOpener
Und es läuft immer noch genauso (schlecht), und ich habe auch die gespeicherte Prozedur in geändert
CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *, 'recompile please'
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
Und wieder zurück, um es wirklich zum Neukompilieren zu bringen.
Ich habe die gespeicherte Prozedur gelöscht und neu erstellt, damit sie einen neuen Plan generiert.
Ich habe versucht, Neukompilierungen zu erzwingen und das Schnüffeln von Parametern mithilfe einer Täuschungsvariablen zu verhindern:
CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
DECLARE @SessionGUIDbitch uniqueidentifier
SET @SessionGUIDbitch = @SessionGUID
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUIDbitch
ORDER BY CurrencyTypeOrder, Rank
Ich habe auch versucht, die gespeicherte Prozedur zu definieren WITH RECOMPILE
:
CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier
WITH RECOMPILE
AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
Damit der Plan nie zwischengespeichert wird, habe ich versucht, bei der Ausführung eine Neukompilierung zu erzwingen:
EXECUTE ViewOpener @SessionGUID WITH RECOMPILE
Was nicht geholfen hat.
Ich habe versucht, die Prozedur in dynamisches SQL zu konvertieren:
CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier
WITH RECOMPILE AS
DECLARE @SQLString NVARCHAR(500)
SET @SQLString = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank'
EXECUTE sp_executesql @SQLString,
N'@SessionGUID uniqueidentifier',
@SessionGUID
Was nicht geholfen hat.
Die Entität " Report_Opener
" ist eine Ansicht, die nicht indiziert ist. Die Ansicht verweist nur auf zugrunde liegende Tabellen. Keine Tabelle enthält berechnete Spalten, indiziert oder anderweitig.
Zum Teufel habe ich versucht, die Ansicht mit zu erstellen
SET ANSI_NULLS ON
SET QUOTED_IDENTIFER ON
Das hat es nicht behoben.
Wie kommt es, dass
- Die Abfrage ist schnell
- Das Verschieben der Abfrage in eine Ansicht und das Auswählen aus der Ansicht ist schnell
- Die Auswahl aus der Ansicht einer gespeicherten Prozedur ist 40x langsamer.
Ich habe versucht, die Definition der Ansicht direkt in die gespeicherte Prozedur zu verschieben (Verletzung von 3 Geschäftsregeln und Aufheben einer wichtigen Kapselung), und das macht sie nur etwa 6x langsamer.
Warum ist die Version der gespeicherten Prozedur so langsam? Was kann möglicherweise dazu führen, dass SQL Server Ad-hoc-SQL schneller ausführt als eine andere Art von Ad-hoc-SQL?
Ich würde wirklich lieber nicht
- Betten Sie die SQL in Code ein
Ändern Sie den Code überhaupt
Microsoft SQL Server 2000 - 8.00.2050 (Intel X86) Mar 7 2008 21:29:56 Copyright (c) 1988-2003 Microsoft Corporation Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
Aber was kann dafür verantwortlich sein, dass SQL Server nicht so schnell ausgeführt werden kann wie SQL Server, der eine Abfrage ausführt, wenn nicht das Parameter-Sniffing.
Mein nächster Versuch wird es sein, hat StoredProcedureA
Anruf StoredProcedureB
Anruf StoredProcedureC
Anruf StoredProcedureD
die Ansicht abzufragen.
Wenn dies nicht der Fall ist, lassen Sie die gespeicherte Prozedur eine gespeicherte Prozedur aufrufen, eine UDF aufrufen, eine UDF aufrufen, eine gespeicherte Prozedur aufrufen und eine UDF aufrufen, um die Ansicht abzufragen.
Zusammenfassend lässt sich sagen, dass die folgenden Schritte schnell von der Qualitätssicherung ausgeführt werden, jedoch langsam, wenn sie in eine gespeicherte Prozedur gestellt werden:
Das Original:
--Runs fine outside of a stored procedure
SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
sp_executesql
::
--Runs fine outside of a stored procedure
DECLARE @SQLString NVARCHAR(500)
SET @SQLString = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank'
EXECUTE sp_executesql @SQLString,
N'@SessionGUID uniqueidentifier',
@SessionGUID
EXEC(@sql)
::
--Runs fine outside of a stored procedure
DECLARE @sql NVARCHAR(500)
SET @sql = N'SELECT *
FROM Report_OpenerTest
WHERE SessionGUID = '''+CAST(@SessionGUID AS varchar(50))+'''
ORDER BY CurrencyTypeOrder, Rank'
EXEC(@sql)
Ausführungspläne
Der gute Plan:
|--Sort(ORDER BY:([Expr1020] ASC, [Currencies].[Rank] ASC))
|--Compute Scalar(DEFINE:([Expr1020]=If ([Currencies].[CurrencyType]='ctCanadianCash') then 1 else If ([Currencies].[CurrencyType]='ctMiscellaneous') then 2 else If ([Currencies].[CurrencyType]='ctTokens') then 3 else If ([Currencies].[CurrencyType]
|--Nested Loops(Left Outer Join, OUTER REFERENCES:([Openers].[OpenerGUID]))
|--Filter(WHERE:((([Currencies].[IsActive]<>0 AND [Currencies].[OnOpener]<>0) AND ((((((([Currencies].[CurrencyType]='ctUSCoin' OR [Currencies].[CurrencyType]='ctMiscellaneousUS') OR [Currencies].[CurrencyType]='ctUSCash') OR [Currencies].
| |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Currencies].[CurrencyGUID], [Openers].[OpenerGUID]) WITH PREFETCH)
| |--Nested Loops(Left Outer Join)
| | |--Bookmark Lookup(BOOKMARK:([Bmk1016]), OBJECT:([GrobManagementSystemLive].[dbo].[Windows]))
| | | |--Nested Loops(Inner Join, OUTER REFERENCES:([Openers].[WindowGUID]))
| | | |--Bookmark Lookup(BOOKMARK:([Bmk1014]), OBJECT:([GrobManagementSystemLive].[dbo].[Openers]))
| | | | |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_SessionGUID]), SEEK:([Openers].[SessionGUID]=[@SessionGUID]) ORDERED FORWARD)
| | | |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Windows].[IX_Windows]), SEEK:([Windows].[WindowGUID]=[Openers].[WindowGUID]) ORDERED FORWARD)
| | |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
| |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID] AND [OpenerDetails].[CurrencyGUID]=[Currenc
|--Hash Match(Cache, HASH:([Openers].[OpenerGUID]), RESIDUAL:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]))
|--Stream Aggregate(DEFINE:([Expr1006]=SUM(If (((([Currencies].[CurrencyType]='ctMiscellaneous' OR [Currencies].[CurrencyType]='ctTokens') OR [Currencies].[CurrencyType]='ctChips') OR [Currencies].[CurrencyType]='ctCanadianCoin') OR [
|--Nested Loops(Inner Join, OUTER REFERENCES:([OpenerDetails].[CurrencyGUID]) WITH PREFETCH)
|--Nested Loops(Inner Join)
| |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_OneOpenerPerSession]), SEEK:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
| |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
|--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[PK_Currencies_CurrencyGUID]), SEEK:([Currencies].[CurrencyGUID]=[OpenerDetails].[CurrencyGUID]) ORDERED FORWARD)
Der schlechte Plan
|--Sort(ORDER BY:([Expr1020] ASC, [Currencies].[Rank] ASC))
|--Compute Scalar(DEFINE:([Expr1020]=If ([Currencies].[CurrencyType]='ctCanadianCash') then 1 else If ([Currencies].[CurrencyType]='ctMiscellaneous') then 2 else If ([Currencies].[CurrencyType]='ctTokens') then 3 else If ([Currencies].[Currency
|--Nested Loops(Left Outer Join, OUTER REFERENCES:([Openers].[OpenerGUID]))
|--Filter(WHERE:((([Currencies].[IsActive]<>0 AND [Currencies].[OnOpener]<>0) AND ((((((([Currencies].[CurrencyType]='ctUSCoin' OR [Currencies].[CurrencyType]='ctMiscellaneousUS') OR [Currencies].[CurrencyType]='ctUSCash') OR [Currenc
| |--Nested Loops(Left Outer Join, OUTER REFERENCES:([Currencies].[CurrencyGUID], [Openers].[OpenerGUID]) WITH PREFETCH)
| |--Filter(WHERE:([Openers].[SessionGUID]=[@SessionGUID]))
| | |--Concatenation
| | |--Nested Loops(Left Outer Join)
| | | |--Table Spool
| | | | |--Hash Match(Inner Join, HASH:([Windows].[WindowGUID])=([Openers].[WindowGUID]), RESIDUAL:([Windows].[WindowGUID]=[Openers].[WindowGUID]))
| | | | |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Windows].[IX_Windows_CageGUID]))
| | | | |--Table Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Openers]))
| | | |--Table Spool
| | | |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
| | |--Compute Scalar(DEFINE:([Openers].[OpenerGUID]=NULL, [Openers].[SessionGUID]=NULL, [Windows].[UseChipDenominations]=NULL))
| | |--Nested Loops(Left Anti Semi Join)
| | |--Clustered Index Scan(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[IX_Currencies_CurrencyType]))
| | |--Row Count Spool
| | |--Table Spool
| |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID] AND [OpenerDetails].[CurrencyGUID]=[Cu
|--Hash Match(Cache, HASH:([Openers].[OpenerGUID]), RESIDUAL:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]))
|--Stream Aggregate(DEFINE:([Expr1006]=SUM([partialagg1034]), [Expr1007]=SUM([partialagg1035]), [Expr1008]=SUM([partialagg1036]), [Expr1009]=SUM([partialagg1037]), [Expr1010]=SUM([partialagg1038]), [Expr1011]=SUM([partialagg1039]
|--Nested Loops(Inner Join)
|--Stream Aggregate(DEFINE:([partialagg1034]=SUM(If (((([Currencies].[CurrencyType]='ctMiscellaneous' OR [Currencies].[CurrencyType]='ctTokens') OR [Currencies].[CurrencyType]='ctChips') OR [Currencies].[CurrencyType]='
| |--Nested Loops(Inner Join, OUTER REFERENCES:([OpenerDetails].[CurrencyGUID]) WITH PREFETCH)
| |--Clustered Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[OpenerDetails].[IX_OpenerDetails_OpenerGUIDCurrencyGUID]), SEEK:([OpenerDetails].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
| |--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Currencies].[PK_Currencies_CurrencyGUID]), SEEK:([Currencies].[CurrencyGUID]=[OpenerDetails].[CurrencyGUID]) ORDERED FORWARD)
|--Index Seek(OBJECT:([GrobManagementSystemLive].[dbo].[Openers].[IX_Openers_OneOpenerPerSession]), SEEK:([Openers].[OpenerGUID]=[Openers].[OpenerGUID]) ORDERED FORWARD)
Der Böse spult eifrig 6 Millionen Zeilen; der andere ist es nicht.
Hinweis: Dies ist keine Frage zum Optimieren einer Abfrage. Ich habe eine Abfrage, die blitzschnell ausgeführt wird. Ich möchte nur, dass SQL Server von einer gespeicherten Prozedur aus schnell ausgeführt wird.
quelle
Antworten:
Ich hatte das gleiche Problem wie das Originalplakat, aber die zitierte Antwort löste das Problem für mich nicht. Die Abfrage wurde von einer gespeicherten Prozedur immer noch sehr langsam ausgeführt.
Ich habe hier eine andere Antwort gefunden "Parameter Sniffing" , danke Omnibuzz. Es läuft darauf hinaus, "lokale Variablen" in Ihren Abfragen für gespeicherte Prozeduren zu verwenden, aber lesen Sie das Original, um es besser zu verstehen. Es ist eine großartige Zusammenfassung. z.B
Langsamer Weg:
Der schnelle Weg:
Ich hoffe, dies hilft jemand anderem. Dadurch wurde meine Ausführungszeit von mehr als 5 Minuten auf etwa 6 bis 7 Sekunden reduziert.
quelle
WITH RECOMPILE
machte für mich keinen Unterschied, nur die lokalen Parameter.Ich habe das Problem gefunden. Hier ist das Skript der langsamen und schnellen Versionen der gespeicherten Prozedur:
dbo.ViewOpener__RenamedForCruachan__Slow.PRC
dbo.ViewOpener__RenamedForCruachan__Fast.PRC
Wenn Sie den Unterschied nicht bemerkt haben, beschuldige ich Sie nicht. Der Unterschied liegt überhaupt nicht in der gespeicherten Prozedur. Der Unterschied, der aus einer schnellen Abfrage mit 0,5 Kosten eine Abfrage mit einer eifrigen Spule von 6 Millionen Zeilen macht:
Langsam:
SET ANSI_NULLS OFF
Schnell:
SET ANSI_NULLS ON
Diese Antwort könnte auch sinnvoll sein, da die Ansicht eine Join-Klausel enthält, die besagt:
Es sind also einige
NULL
beteiligt.Die Erklärung wird weiter bewiesen, indem Sie zu Query Analizer zurückkehren und ausführen
.
.
Und die Abfrage ist langsam.
Das Problem liegt also nicht darin, dass die Abfrage von einer gespeicherten Prozedur ausgeführt wird. Das Problem ist , dass Enterprise Manager der Verbindung Standardoption ist
ANSI_NULLS off
, und nichtANSI_NULLS on
, das ist Standard QA.Microsoft erkennt diese Tatsache in KB296769 an (BUG: SQL Enterprise Manager kann nicht zum Erstellen gespeicherter Prozeduren mit verknüpften Serverobjekten verwendet werden). Die Problemumgehung besteht darin, die
ANSI_NULLS
Option in das Dialogfeld für gespeicherte Prozeduren aufzunehmen:quelle
ANSI_NULLS ON
einen so enormen Leistungsunterschied macht.JOIN
Klauseln in der Ansicht unterschiedliche Bedeutung haben, wennANSI_NULLS OFF
. Plötzlich stimmen die Zeilen überein, sodass das Optimierungsprogramm die Abfrage völlig anders ausführt. Stellen Sie sich vor, anstatt 99,9% aller Zeilen zu eliminieren, kehren sie plötzlich zurück.ANSI_NULLS OFF
ist veraltet und als eine schlechte PraxisTun Sie dies für Ihre Datenbank. Ich habe das gleiche Problem - es funktioniert einwandfrei in einer Datenbank, aber wenn ich diese Datenbank mithilfe des SSIS-Imports in eine andere kopiere (nicht die übliche Wiederherstellung), tritt dieses Problem bei den meisten meiner gespeicherten Prozeduren auf. Nachdem ich noch ein bisschen gegoogelt hatte, fand ich den Blog von Pinal Dave (der übrigens den größten Teil seines Beitrags traf und mir sehr geholfen hat, danke Pinal Dave) .
Ich führe die folgende Abfrage in meiner Datenbank aus und sie hat mein Problem behoben:
Hoffe das hilft. Ich gebe nur die Hilfe von anderen weiter, die mir geholfen haben.
quelle
DBCC REINDEX
wurde veraltet, daher sollten Sie nach Alternativen suchen.DBCC DBREINDEX
, MS sagt: "Diese Funktion wird in einer zukünftigen Version von Microsoft SQL Server entfernt. Verwenden Sie diese Funktion nicht in neuen Entwicklungsarbeiten und ändern Sie Anwendungen, die diese Funktion derzeit verwenden, so bald wie möglich. Verwenden Sie stattdessen ALTER INDEX."Ich hatte das gleiche Problem und dieser Beitrag war sehr hilfreich für mich, aber keine der veröffentlichten Antworten löste mein spezifisches Problem. Ich wollte die Lösung veröffentlichen, die für mich funktioniert hat, in der Hoffnung, dass sie jemand anderem helfen kann.
https://stackoverflow.com/a/24016676/814299
quelle
Diesmal haben Sie Ihr Problem gefunden. Wenn Sie das nächste Mal weniger Glück haben und es nicht herausfinden können, können Sie Plan Freezing verwenden und sich keine Gedanken mehr über falsche Ausführungspläne machen.
quelle
Ich hatte dieses Problem. Meine Anfrage sah ungefähr so aus:
Meine gespeicherte Prozedur wurde wie folgt definiert:
Ich habe den Datentyp in datetime und voila geändert! Ging von 30 Minuten bis 1 Minute!
quelle
Haben Sie versucht, die Statistiken und / oder Indizes in der Tabelle Report_Opener neu zu erstellen? Alle Wiederholungen des SP sind nichts wert, wenn die Statistiken noch Daten aus der Zeit zeigen, als die Datenbank zum ersten Mal eröffnet wurde.
Die anfängliche Abfrage selbst funktioniert schnell, da der Optimierer erkennen kann, dass der Parameter niemals null sein wird. Im Fall des SP kann der Optimierer nicht sicher sein, dass der Parameter niemals null sein wird.
quelle
Obwohl ich normalerweise dagegen bin (obwohl es in diesem Fall so aussieht, als hätten Sie einen echten Grund), haben Sie versucht, Abfragehinweise zur SP-Version der Abfrage bereitzustellen? Wenn SQL Server in diesen beiden Fällen einen anderen Ausführungsplan vorbereitet, können Sie anhand eines Hinweises angeben, welcher Index verwendet werden soll, damit der Plan mit dem ersten übereinstimmt.
Einige Beispiele finden Sie hier .
BEARBEITEN: Wenn Sie Ihren Abfrageplan hier veröffentlichen können, können wir möglicherweise einen Unterschied zwischen den aussagekräftigen Plänen feststellen.
ZWEITENS: Der Link wurde so aktualisiert, dass er SQL-2000-spezifisch ist. Sie müssen ein Stück nach unten scrollen, aber es gibt eine zweite mit dem Titel "Table Hints", nach der Sie suchen.
DRITTES: Die "Bad" -Abfrage scheint die [IX_Openers_SessionGUID] in der "Openers" -Tabelle zu ignorieren. Gibt es eine Möglichkeit, einen INDEX-Hinweis hinzuzufügen, um die Verwendung dieses Index zu erzwingen?
quelle
Dies ist wahrscheinlich unwahrscheinlich, aber da Ihr beobachtetes Verhalten ungewöhnlich ist, muss es überprüft werden und niemand anderes hat es erwähnt.
Sind Sie absolut sicher, dass alle Objekte im Besitz von dbo sind und Sie keine betrügerischen Kopien von sich selbst oder einem anderen Benutzer haben?
Nur gelegentlich, wenn ich merkwürdiges Verhalten gesehen habe, liegt es daran, dass es tatsächlich zwei Kopien eines Objekts gab und welche Sie erhalten, hängt davon ab, was angegeben ist und als wen Sie angemeldet sind. Zum Beispiel ist es durchaus möglich, zwei Kopien einer Ansicht oder Prozedur mit demselben Namen zu haben, die sich jedoch im Besitz verschiedener Eigentümer befinden. Dies kann vorkommen, wenn Sie nicht als Datenbankbenutzer in der Datenbank angemeldet sind und vergessen, dbo als Objekteigentümer anzugeben, wenn Sie erstellen das Objekt.
Beachten Sie, dass Sie im Text einige Dinge ausführen, ohne den Eigentümer anzugeben, z
Wenn beispielsweise zwei Kopien von viewOpener vorhanden sind, die dbo und [einem anderen Benutzer] gehören, hängt es von den Umständen ab, welche Sie tatsächlich neu kompilieren, wenn Sie nichts angeben. Das Gleiche gilt für die Ansicht "Report_Opener". Wenn zwei Kopien vorhanden sind (und sich in Spezifikation oder Ausführungsplan unterscheiden können), hängt die Verwendung von den Umständen ab. Da Sie keinen Eigentümer angeben, ist es durchaus möglich, dass Ihre Ad-hoc-Abfrage eine und die verwendet Die kompilierte Prozedur verwendet möglicherweise die andere.
Wie gesagt, es ist wahrscheinlich unwahrscheinlich, aber es ist möglich und sollte überprüft werden, da Ihre Probleme darin bestehen könnten, dass Sie einfach am falschen Ort nach dem Fehler suchen.
quelle
Dies mag albern klingen und scheint aus dem Namen SessionGUID ersichtlich zu sein, aber ist die Spalte eine eindeutige Kennung in Report_Opener? Wenn nicht, können Sie versuchen, es in den richtigen Typ umzuwandeln und es zu versuchen, oder Ihre Variable zum richtigen Typ deklarieren.
Der als Teil des Sproc erstellte Plan funktioniert möglicherweise nicht intuitiv und führt eine interne Besetzung auf einem großen Tisch durch.
quelle
varchar
Spalte mit einemnvarchar
Wert (zBWHERE CustomerName = N'zrendall'
) verglichen hat . SQL Server musstenvarchar
vor dem Vergleich jeden Spaltenwert in einen konvertieren .Ich habe eine andere Idee. Was ist, wenn Sie diese tabellenbasierte Funktion erstellen:
Und dann mit der folgenden Anweisung daraus auswählen (sogar in Ihren SP einfügen):
Es sieht so aus, als ob SQL Server nur eine Annahme macht, die falsch ist, und dies zwingt ihn möglicherweise, die Annahme zu korrigieren. Ich hasse es, den zusätzlichen Schritt hinzuzufügen, bin mir aber nicht sicher, was ihn sonst noch verursachen könnte.
quelle
- Hier ist die Lösung:
-- Das ist es
quelle