8

C#ASP.NetアプリケーションからSQL関数(UDF)を呼び出しています。私が呼び出している関数には、「uniqueidentifier」タイプのパラメーターが1つ必要です。

呼び出しを行い、SqlCommandのCommandTextで「null」を渡すと、結果は約3秒で返されます...

SqlCommand Command = new SqlCommand();
Command.Connection = (SqlConnection)(DbDataModifier.CreateConnection());
Command.CommandText = "select * from GetLocalFirmLoginsSummary(null) order by Date asc"
Command.CommandType = CommandType.Text;

Command.Connection.Open();

SqlDataReader Reader = Command.ExecuteReader(); // takes 3 seconds

しかし、呼び出しを行ってDBNull.ValueをSqlParameterとして渡すと、結果が返されるまでに60秒以上かかります...

SqlCommand Command = new SqlCommand();
Command.Connection = (SqlConnection)(DbDataModifier.CreateConnection());
Command.CommandText = "select * from GetLocalFirmLoginsSummary(@CustomerGroupID) order by Date asc"
Command.CommandType = CommandType.Text;

SqlParameter Param = new SqlParameter();
Param.ParameterName = "@CustomerGroupID";
Param.SqlDbType = SqlDbType.UniqueIdentifier;
Param.Direction = ParameterDirection.Input;
Param.IsNullable = true;
Param.Value = DBNull.Value;
Command.Parameters.Add(Param);

Command.Connection.Open();

SqlDataReader Reader = Command.ExecuteReader(); // takes over 60 seconds

SQL Management Studioで同じクエリを実行すると、パラメータとしてnullを渡した場合でも、約3秒かかります...

declare @CustomerGroupID uniqueidentifier
set @CustomerGroupID = null

select * from GetLocalFirmLoginsSummary(@CustomerGroupID)

私が呼び出している関数は次のように定義されています。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[GetLocalFirmLoginsSummary]
(   
    @CustomerGroupID uniqueidentifier
)
RETURNS TABLE 
AS
RETURN 
(

SELECT     CustomerGroupID, CustomerGroupName, USR, DATEADD(MONTH, DATEDIFF(MONTH, 0, createdDate), 0) AS Date, COUNT(*) AS Quantity
FROM         dbo.GetLocalFirmLogins(@CustomerGroupID) AS Logins
GROUP BY USR, CustomerGroupID, CustomerGroupName, DATEADD(MONTH, DATEDIFF(MONTH, 0, createdDate), 0)

)

..。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[GetLocalFirmLogins]
(   
@CustomerGroupID uniqueidentifier
)
RETURNS TABLE 
AS
RETURN 
(

SELECT     vw_CustomerGroupAccountDetails.CustomerGroupID, vw_CustomerGroupAccountDetails.CustomerGroupName, Organisations.USR, Organisations.town AS FirmTown, 
                  Users.id AS ID, Users.userName, Users.password, Users.isPartner, Users.isFeeEarner, Users.nlisUserName, Users.nlisPassword, Users.email, Users.lastLoginDate, Users.createdDate
FROM         vw_CustomerGroupAccountDetails RIGHT OUTER JOIN
                      Organisations ON vw_CustomerGroupAccountDetails.AccountID = CAST(Organisations.id AS nvarchar(50)) RIGHT OUTER JOIN
                  Users ON Organisations.clientId = Users.uploadedBy
WHERE     (Users.canLogin = 1) AND (Users.isDeleted = 0) AND (NOT (Organisations.USR IS NULL)) AND 
                      ((vw_CustomerGroupAccountDetails.CustomerGroupID = @CustomerGroupID) OR (@CustomerGroupID IS NULL))

)

では、SqlCommandのSqlParameterを使用してC#からSQL関数を呼び出すと、何が原因でこれほど時間がかかるのでしょうか。

SQLServer2000を使用しています。

私はどこでも、考えられるあらゆる方法で検索しましたが、同じ問題を抱えている人を他に見つけることはできません。

4

3 に答える 3

1

SQLServerのパラメータスニッフィングの問題が原因である可能性があります。

詳細については、次のリンクをご覧ください。

パラメータスニッフィング

これがお役に立てば幸いです。

于 2012-07-10T08:44:39.277 に答える
1

ジム、dbo.GetLocalFirmLogins のソースを投稿していただけますか?

マーティンが言うように、これはパラメーター スニッフィングである可能性があります。そうである場合、 @CustomerGroupID のシークがこれを「外科的に」修正するための最良の方法である可能性があるコード内のクエリ ヒント。

OPTION (LOOP JOIN) を dbo.GetLocalFirmLogins のクエリに追加すると、ここで修正できます。

C# では問題が発生するのに、SSMS では問題が発生しない理由も説明できると思います。クエリのこの部分:

(CustomerGroupID = @CustomerGroupID) OR (@CustomerGroupID IS NULL) 

接続元の接続の ANSI NULL 設定に応じて、2 つの異なるプランを持つことができます。ANSI NULL であり、効果は次のとおりです。

ANSI_NULLS を設定

このクエリの結果を取得すると、接続の ANSI 設定を確認できます。

DBCC ユーザーオプション

SSMS には、C# コードとは異なる NULL 設定があり、クエリの評価が異なる場合があります。

于 2012-06-14T22:12:05.623 に答える
0

Management Studio と .NET コードのパフォーマンスの違いは、多くの場合、ANSI_NULLS などの設定に関連しています。

これは SQL Server 2000 のバグである可能性があります。CREATE FUNCTION の前に SET ANSI_NULLS ON が考慮されていないことを暗示しているように見えるこの投稿を参照してください。

これをテストするための SQL Server 2000 はありませんが、関数のスクリプトを作成してみてください。

于 2012-06-15T09:26:18.293 に答える