Korzystanie z SQL Server 2008 R2
Mam 20-sekundowe zapytanie z tej funkcji, która używa kursora, pętli while i AND wywołuje inną funkcję.
Na podstawie pokazanego kodu - jaki byłby najlepszy sposób na poprawę wydajności tego wąskiego gardła?
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[ufnGetForUser] (@UserName VARCHAR(100))
RETURNS @User TABLE (
ID INT
,Name VARCHAR(40)
,ParentID INT
,CompanyID INT
,CompanyName VARCHAR(100)
,CompanyDisplayName VARCHAR(100)
,AnotherID INT
,AnotherName VARCHAR(50)
)
AS
BEGIN
DECLARE @List TABLE (
ID INT
,Name VARCHAR(40)
,ParentID INT
)
DECLARE List CURSOR
FOR
SELECT ID
FROM YourTable WITH (NOLOCK)
WHERE CompanyID IN (
SELECT companyid
FROM UserToCompany
WHERE UserName = @UserName
)
DECLARE @ID AS INT
OPEN List
FETCH List
INTO @id
WHILE (@@FETCH_STATUS = 0)
BEGIN
INSERT INTO @List
SELECT *
FROM ufnIncludeWithChildren(@ID)
FETCH List
INTO @ID
END
CLOSE List
DEALLOCATE List
INSERT INTO @User
SELECT DISTINCT a.ID
,a.Name
,a.ParentID
,c.CompanyID
,c.CompanyName
,c.CompanyDisplayName
,d.AnotherID
,d.AnotherName
FROM @List a
JOIN YourTable b ON a.ID = b.ID
JOIN CompanyInfo c ON b.CompanyID = c.CompanyID
JOIN Anothers d ON b.AnotherID = d.AnotherID
RETURN
END
Odpowiedzi:
3 dla odpowiedzi № 1Powinieneś być w stanie użyć jednego wyboru.
USE [DB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[ufnGetForUser] (@UserName VARCHAR(100))
RETURNS @User TABLE (
ID INT
,Name VARCHAR(40)
,ParentID INT
,CompanyID INT
,CompanyName VARCHAR(100)
,CompanyDisplayName VARCHAR(100)
,AnotherID INT
,AnotherName VARCHAR(50)
)
AS
BEGIN
INSERT INTO @User
SELECT DISTINCT a.ID
,a.Name
,a.ParentID
,c.CompanyID
,c.CompanyName
,c.CompanyDisplayName
,d.AnotherID
,d.AnotherName
FROM UserToCompany u
JOIN CompanyInfo c ON u.CompanyID = c.CompanyID
CROSS APPLY ufnIncludeWithChildren(yt.ID) a
JOIN YourTable b ON a.ID = b.ID
JOIN Anothers d ON b.AnotherID = d.AnotherID
WHERE u.UserName = @UserName
RETURN
END
2 dla odpowiedzi nr 2
Na pierwszy rzut oka możemy zdecydowanie wyeliminować CURSOR
. Podczas zastępowania go przez WHILE
Pętla, ponieważ w moim komentarzu jest jedno rozwiązanie, możemy pójść o krok dalej i całkowicie wyeliminować pętlę, używając APPLY
klauzula wywoływania funkcji bezpośrednio dla każdej wartości w wierszu.
ALTER FUNCTION [dbo].[ufnGetForUser] (@UserName VARCHAR(100))
RETURNS @User TABLE (
ID INT
,Name VARCHAR(40)
,ParentID INT
,CompanyID INT
,CompanyName VARCHAR(100)
,CompanyDisplayName VARCHAR(100)
,AnotherID INT
,AnotherName VARCHAR(50)
)
AS
BEGIN
DECLARE @List TABLE (
ID INT
,Name VARCHAR(40)
,ParentID INT
)
INSERT INTO @List
SELECT sfn.*
FROM YourTable yt WITH (NOLOCK)
CROSS APPLY ufnIncludeWithChildren(yt.ID) sfn
WHERE yt.CompanyID IN (
SELECT companyid
FROM UserToCompany
WHERE UserName = @UserName
)
INSERT INTO @User
SELECT DISTINCT a.ID
,a.Name
,a.ParentID
,c.CompanyID
,c.CompanyName
,c.CompanyDisplayName
,d.AnotherID
,d.AnotherName
FROM @List a
JOIN b ON a.ID = b.ID
JOIN CompanyInfo c ON b.CompanyID = c.CompanyID
JOIN Anothers d ON b.AnotherID = d.AnotherID
RETURN
END
Ten kod nie jest testowany, ale powinien działać. Daj mi znać, jeśli masz jakieś problemy.
Również w swoim pytaniu pominąłeś nazwę tabeli z pierwszego zapytania (w którym miałeś kursor), więc wstawiłem YourTable
tam jako symbol zastępczy.