我正在使用此代码调用SQL函数,该函数返回SQL Server数据库表中的条目
string cmd = String.Format("select * from dbo.GetData(@userId, @fileId, @created);");
using (SqlConnection conn = new SqlConnection(connectionString))
{
if (conn.State != ConnectionState.Open)
conn.Open();
SqlCommand command = new SqlCommand(cmd, conn);
if (String.IsNullOrEmpty(userId))
command.Parameters.AddWithValue("@userId", DBNull.Value);
else
command.Parameters.AddWithValue("@userId", userId);
if (String.IsNullOrEmpty(fileId))
command.Parameters.AddWithValue("@fileId", DBNull.Value);
else
command.Parameters.AddWithValue("@fileId", docId);
command.Parameters.AddWithValue("@created", created);
internalWatch.Reset();
internalWatch.Start();
IDataReader reader = command.ExecuteReader();
table = GetDataTableFromDataReader(reader);
reader.Close();
reader.Dispose();
conn.Close();
internalWatch.Stop();
我正在使用的表包含超过150万个条目,并且应该返回超过250,000个条目。
如果我在SSMS中执行SQL函数,则需要8秒才能返回结果,并且我已经使用上周的代码在我的桌面应用程序中获取结果。这时一切都很好。代码需要10-12秒才能得到结果。
奇怪的是,今天代码需要超过40秒才能返回相同的结果,但我还没有改变SQL函数或代码本身的任何内容。我在我的程序中做的唯一改变是添加了一些类,这与上面的代码无关。
如果我正在调试代码,我可以看到,该行
IDataReader reader = command.ExecuteReader();
现在需要大部分时间。
由于我没有改变SQL函数或代码本身的任何内容,我无法理解为什么它需要这么长时间......
如果需要,这是SQL函数,我正在使用:
ALTER FUNCTION [dbo].[GetData]
(@userId varchar(128) = NULL,
@fileId varchar(192) = NULL,
@created DateTimeOffset(7))
RETURNS TABLE
AS
RETURN (
WITH FindNewestVersion AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITINO BY FileId, UserId
ORDER BY created DESC) rn
FROM
table1
)
SELECT
q.Created, q.Updated, q.FileId, q.UserId,
F.column1, F.column2, F.column3
FROM
table2 AS F
INNER JOIN
table1 AS q ON F.column4 = q.PersonId AND F.created = q.created
INNER JOIN
(SELECT
created, PersonId, DocumentId
FROM
FindNewestVersion
WHERE
rn = 1) AS x ON q.created = x.created
AND q.PersonId = x.PersonId
AND q.FileId = x.FileId
WHERE
(F.column1 = 'Sample')
AND (q.Created <= @created)
AND (q.Updated >= @created)
AND Q.PersonId = ISNULL(@userId, Q.PersonId)
AND Q.FileId = ISNULL(@fileId, Q.FileId)
)
感谢您的任何建议!
答案 0 :(得分:3)
这似乎是参数嗅探的一种情况
您可以做的一件事是按以下步骤重写您的程序:
`
DROP FUNCTION [dbo].[GetData]
CREATE PROCEDURE[dbo].[GetData]
(
@userId varchar(128) = NULL,
@fileId varchar(192) = NULL,
@created DateTimeOffset(7)
)
RETURNS TABLE
AS
DECLARE @l_userId varchar(128) = NULL,
DECLARE @l_fileId varchar(192) = NULL,
DECLARE @l_created DateTimeOffset(7)
SET @l_userId = userId
SET @l_fileId = fileId
SET @l_created = @created
(
WITH FindNewestVersion as
(
Select *, ROW_NUMBER()
over (partition by FileId, UserId ORDER BY created DESC)rn from table1
)
SELECT q.Created, q.Updated, q.FileId, q.UserId,
F.column1, F.column2, F.column3
FROM table2 AS F INNER JOIN
table1 AS q
ON F.column4 = q.PersonId AND F.created = q.created
INNER JOIN
(
select created, PersonId, DocumentId from FindNewestVersion where rn = 1
) AS x ON q.created = x.created AND q.PersonId = x.PersonId AND q.FileId = x.FileId
WHERE (F.column1 = 'Sample') AND (q.Created <= @created) AND (q.Updated >= @created)
And Q.PersonId = ISNULL(@l_userId, Q.PersonId)
And Q.FileId = ISNULL(@l_fileId, Q.FileId)
)
` 然后,您可以通过调用存储过程来获取数据。
答案 1 :(得分:0)
这似乎是SET ARITHABORT ON的情况
SQL默认情况下为On,但是当我们通过C#代码执行时,它不了解ARITHABORT ON。
您可以做的一件事是如下重写程序:
DROP FUNCTION [dbo].[GetData]
CREATE PROCEDURE[dbo].[GetData]
(
@userId varchar(128) = NULL,
@fileId varchar(192) = NULL,
@created DateTimeOffset(7)
)
RETURNS TABLE
AS
SET ARITHABORT ON
DECLARE @l_userId varchar(128) = NULL,
DECLARE @l_fileId varchar(192) = NULL,
DECLARE @l_created DateTimeOffset(7)
SET @l_userId = userId
SET @l_fileId = fileId
SET @l_created = @created
(
WITH FindNewestVersion as
(
Select *, ROW_NUMBER()
over (partition by FileId, UserId ORDER BY created DESC)rn from table1
)
SELECT q.Created, q.Updated, q.FileId, q.UserId,
F.column1, F.column2, F.column3
FROM table2 AS F INNER JOIN
table1 AS q
ON F.column4 = q.PersonId AND F.created = q.created
INNER JOIN
(
select created, PersonId, DocumentId from FindNewestVersion where rn = 1
) AS x ON q.created = x.created AND q.PersonId = x.PersonId AND q.FileId = x.FileId
WHERE (F.column1 = 'Sample') AND (q.Created <= @created) AND (q.Updated >= @created)
And Q.PersonId = ISNULL(@l_userId, Q.PersonId)
And Q.FileId = ISNULL(@l_fileId, Q.FileId)
)`enter code here`