SQL ROWCOUNT 检查的性能 - 更好的方法?
SQL performance on ROWCOUNT check - better way?
我有一个 MS SQL 2005 存储过程,我将 ID 从网页传递给它。
该 ID 用于从小部件类别登陆页面的数据库中将预设搜索条件读取到一组变量中。
然后在 SELECT 中使用这些变量来搜索小部件项目的数据库。一些变量可以被访问者的页面选择覆盖,例如最高价格。
我想检查 SELECT return 是否有记录,如果没有,则默认使用目标网页的正常标准,以确保访问者总能看到一些项目。
我尝试使用@@ROWCOUNT 检查第一个 SELECT 但是,由于 SELECT 相当复杂(我在下面的示例中删除了很多字段), 运行 两次的性能损失长得令人无法接受。第一个 SELECT 本身需要大约 1 秒,而检查 @@ROWCOUNT = 0 和 运行 SELECT 再次需要大约 4 秒。
如果第一个 SELECT returns none?
,是否有更好的方法来完成此检查和 return 记录
我还想 return 在存储过程结束时只有一个记录集,而不是两个。
经过研究,我发现有人在两个选择上使用 UNION ALL,但我认为在这种情况下它对我没有帮助。我还想通过传递内容为 True 或 False 的字段来知道使用了哪个 SELECT,这样我就可以在网站上标记是否没有找到记录。
感谢您的帮助。
CREATE PROCEDURE dbo.NW_LANDING_GET_Widgets
/* options from the web page */
@WidgetID int,
@PageNumber int,
@WidgetsPerPage int,
@Sort VARCHAR(1),
@MinPrice int,
@MaxPrice int,
@Override_WidgetType varchar(20),
@Override_WidgetInfo1 int
AS
SET NOCOUNT ON
BEGIN
/* ---------- Declare variables for criteria to be gathered from WidgetLanding table ------------ */
DECLARE @WidgetCategory1 varchar(50)
DECLARE @WidgetCategory2 varchar(50)
DECLARE @WidgetType varchar(30)
DECLARE @WidgetInfo1 int
/* ---------- Read default criteria into variables from WidgetLanding table ----- */
SELECT
@WidgetCategory1=Criteria_WidgetCategory1,
@WidgetCategory2=Criteria_WidgetCategory2,
@WidgetType=Criteria_WidgetType
FROM dbo.WidgetLanding
WHERE pk_WidgetID = @WidgetID
/* -------- Set PageNumber variable for SELECT of Widgets ----------- */
SET @PageNumber=(@PageNumber-1)*@WidgetsPerPage
/* Set Minimum and Maximum Prices - if Null, set highest and lowest number possible */
DECLARE @Min int
DECLARE @Max int
SET @Min = ISNULL(@MinPrice,0)
SET @Max = ISNULL(@MaxPrice,999999999)
/* -------- Override variables if visitor has changed the search criteria from default ------------------- */
IF @Override_WidgetType is not null
BEGIN
SET @WidgetType=@Override_WidgetType
END
IF @Override_WidgetInfo1 is not null
BEGIN
SET @WidgetInfo1=@Override_WidgetInfo1
END
/* ------------------- Retrieve widget records based on variables ------ */
SELECT TOP(@WidgetsPerPage) * FROM (SELECT RowID=ROW_NUMBER()
OVER (ORDER BY
CASE WHEN dbo.Widgets.Featured_WidgetLandingID = @WidgetID then 1 else 0 end DESC,
CASE WHEN @Sort = 'D' THEN dbo.Widgets.Price END DESC, /* Price Descending */
CASE WHEN @Sort = 'U' THEN dbo.Widgets.Price END ASC, /* Price Ascending */
CASE WHEN @Sort = 'P' THEN dbo.Widgets.viewed END DESC, /* Popular */
CASE WHEN @Sort = 'L' THEN dbo.Widgets.Date END DESC), /* Latest */
Count(dbo.Widgets.WidgetID) OVER() As TotalRecords,
dbo.Widgets.Price,
dbo.Widgets.WidgetID,
dbo.Widgets.WidgetCategory1,
dbo.Widgets.WidgetCategory2,
dbo.Widgets.WidgetType,
dbo.Widgets.WidgetType2,
dbo.Widgets.WidgetInfo1
FROM dbo.Widgets
WHERE
(WidgetCategory1 = @WidgetCategory1 OR @WidgetCategory1 is null) AND
(WidgetCategory2 = @WidgetCategory2 OR @WidgetCategory2 is null) AND
(Price >= @Min AND Price <= @Max) AND
(WidgetInfo1 >= @WidgetInfo1 OR @WidgetInfo1 is null)
) TAB WHERE TAB.RowId > CAST(@PageNumber AS INT)
/*
-----------------------------
THIS IS WHERE I WANT TO CHECK IF RECORDS ARE RETURNED - IF NOT DO ANOTHER SELECT BUT WITHOUT OVERRIDING VARIABLES SO RECORDS WILL ALWAYS BE RETURNED
-----------------------------
*/
END
SET NOCOUNT OFF
最简单的方法是这样的代码:
SELECT TOP(@WidgetsPerPage) *
INTO #Res
FROM (SELECT RowID=ROW_NUMBER()
OVER (ORDER BY
CASE WHEN dbo.Widgets.Featured_WidgetLandingID = @WidgetID then 1 else 0 end DESC,
CASE WHEN @Sort = 'D' THEN dbo.Widgets.Price END DESC, /* Price Descending */
CASE WHEN @Sort = 'U' THEN dbo.Widgets.Price END ASC, /* Price Ascending */
CASE WHEN @Sort = 'P' THEN dbo.Widgets.viewed END DESC, /* Popular */
CASE WHEN @Sort = 'L' THEN dbo.Widgets.Date END DESC), /* Latest */
Count(dbo.Widgets.WidgetID) OVER() As TotalRecords,
dbo.Widgets.Price,
dbo.Widgets.WidgetID,
dbo.Widgets.WidgetCategory1,
dbo.Widgets.WidgetCategory2,
dbo.Widgets.WidgetType,
dbo.Widgets.WidgetType2,
dbo.Widgets.WidgetInfo1
FROM dbo.Widgets
WHERE
(WidgetCategory1 = @WidgetCategory1 OR @WidgetCategory1 is null) AND
(WidgetCategory2 = @WidgetCategory2 OR @WidgetCategory2 is null) AND
(Price >= @Min AND Price <= @Max) AND
(WidgetInfo1 >= @WidgetInfo1 OR @WidgetInfo1 is null)
) TAB WHERE TAB.RowId > CAST(@PageNumber AS INT)
IF (@@ROWCOUNT>0)
BEGIN
INSERT #Res (......)
SELECT
END
SELECT * FROM #Res
但无论如何你的查询应该重写。
我有一个 MS SQL 2005 存储过程,我将 ID 从网页传递给它。
该 ID 用于从小部件类别登陆页面的数据库中将预设搜索条件读取到一组变量中。
然后在 SELECT 中使用这些变量来搜索小部件项目的数据库。一些变量可以被访问者的页面选择覆盖,例如最高价格。
我想检查 SELECT return 是否有记录,如果没有,则默认使用目标网页的正常标准,以确保访问者总能看到一些项目。
我尝试使用@@ROWCOUNT 检查第一个 SELECT 但是,由于 SELECT 相当复杂(我在下面的示例中删除了很多字段), 运行 两次的性能损失长得令人无法接受。第一个 SELECT 本身需要大约 1 秒,而检查 @@ROWCOUNT = 0 和 运行 SELECT 再次需要大约 4 秒。
如果第一个 SELECT returns none?
,是否有更好的方法来完成此检查和 return 记录我还想 return 在存储过程结束时只有一个记录集,而不是两个。
经过研究,我发现有人在两个选择上使用 UNION ALL,但我认为在这种情况下它对我没有帮助。我还想通过传递内容为 True 或 False 的字段来知道使用了哪个 SELECT,这样我就可以在网站上标记是否没有找到记录。
感谢您的帮助。
CREATE PROCEDURE dbo.NW_LANDING_GET_Widgets
/* options from the web page */
@WidgetID int,
@PageNumber int,
@WidgetsPerPage int,
@Sort VARCHAR(1),
@MinPrice int,
@MaxPrice int,
@Override_WidgetType varchar(20),
@Override_WidgetInfo1 int
AS
SET NOCOUNT ON
BEGIN
/* ---------- Declare variables for criteria to be gathered from WidgetLanding table ------------ */
DECLARE @WidgetCategory1 varchar(50)
DECLARE @WidgetCategory2 varchar(50)
DECLARE @WidgetType varchar(30)
DECLARE @WidgetInfo1 int
/* ---------- Read default criteria into variables from WidgetLanding table ----- */
SELECT
@WidgetCategory1=Criteria_WidgetCategory1,
@WidgetCategory2=Criteria_WidgetCategory2,
@WidgetType=Criteria_WidgetType
FROM dbo.WidgetLanding
WHERE pk_WidgetID = @WidgetID
/* -------- Set PageNumber variable for SELECT of Widgets ----------- */
SET @PageNumber=(@PageNumber-1)*@WidgetsPerPage
/* Set Minimum and Maximum Prices - if Null, set highest and lowest number possible */
DECLARE @Min int
DECLARE @Max int
SET @Min = ISNULL(@MinPrice,0)
SET @Max = ISNULL(@MaxPrice,999999999)
/* -------- Override variables if visitor has changed the search criteria from default ------------------- */
IF @Override_WidgetType is not null
BEGIN
SET @WidgetType=@Override_WidgetType
END
IF @Override_WidgetInfo1 is not null
BEGIN
SET @WidgetInfo1=@Override_WidgetInfo1
END
/* ------------------- Retrieve widget records based on variables ------ */
SELECT TOP(@WidgetsPerPage) * FROM (SELECT RowID=ROW_NUMBER()
OVER (ORDER BY
CASE WHEN dbo.Widgets.Featured_WidgetLandingID = @WidgetID then 1 else 0 end DESC,
CASE WHEN @Sort = 'D' THEN dbo.Widgets.Price END DESC, /* Price Descending */
CASE WHEN @Sort = 'U' THEN dbo.Widgets.Price END ASC, /* Price Ascending */
CASE WHEN @Sort = 'P' THEN dbo.Widgets.viewed END DESC, /* Popular */
CASE WHEN @Sort = 'L' THEN dbo.Widgets.Date END DESC), /* Latest */
Count(dbo.Widgets.WidgetID) OVER() As TotalRecords,
dbo.Widgets.Price,
dbo.Widgets.WidgetID,
dbo.Widgets.WidgetCategory1,
dbo.Widgets.WidgetCategory2,
dbo.Widgets.WidgetType,
dbo.Widgets.WidgetType2,
dbo.Widgets.WidgetInfo1
FROM dbo.Widgets
WHERE
(WidgetCategory1 = @WidgetCategory1 OR @WidgetCategory1 is null) AND
(WidgetCategory2 = @WidgetCategory2 OR @WidgetCategory2 is null) AND
(Price >= @Min AND Price <= @Max) AND
(WidgetInfo1 >= @WidgetInfo1 OR @WidgetInfo1 is null)
) TAB WHERE TAB.RowId > CAST(@PageNumber AS INT)
/*
-----------------------------
THIS IS WHERE I WANT TO CHECK IF RECORDS ARE RETURNED - IF NOT DO ANOTHER SELECT BUT WITHOUT OVERRIDING VARIABLES SO RECORDS WILL ALWAYS BE RETURNED
-----------------------------
*/
END
SET NOCOUNT OFF
最简单的方法是这样的代码:
SELECT TOP(@WidgetsPerPage) *
INTO #Res
FROM (SELECT RowID=ROW_NUMBER()
OVER (ORDER BY
CASE WHEN dbo.Widgets.Featured_WidgetLandingID = @WidgetID then 1 else 0 end DESC,
CASE WHEN @Sort = 'D' THEN dbo.Widgets.Price END DESC, /* Price Descending */
CASE WHEN @Sort = 'U' THEN dbo.Widgets.Price END ASC, /* Price Ascending */
CASE WHEN @Sort = 'P' THEN dbo.Widgets.viewed END DESC, /* Popular */
CASE WHEN @Sort = 'L' THEN dbo.Widgets.Date END DESC), /* Latest */
Count(dbo.Widgets.WidgetID) OVER() As TotalRecords,
dbo.Widgets.Price,
dbo.Widgets.WidgetID,
dbo.Widgets.WidgetCategory1,
dbo.Widgets.WidgetCategory2,
dbo.Widgets.WidgetType,
dbo.Widgets.WidgetType2,
dbo.Widgets.WidgetInfo1
FROM dbo.Widgets
WHERE
(WidgetCategory1 = @WidgetCategory1 OR @WidgetCategory1 is null) AND
(WidgetCategory2 = @WidgetCategory2 OR @WidgetCategory2 is null) AND
(Price >= @Min AND Price <= @Max) AND
(WidgetInfo1 >= @WidgetInfo1 OR @WidgetInfo1 is null)
) TAB WHERE TAB.RowId > CAST(@PageNumber AS INT)
IF (@@ROWCOUNT>0)
BEGIN
INSERT #Res (......)
SELECT
END
SELECT * FROM #Res
但无论如何你的查询应该重写。