采用此处定义的(简化)存储过程:
create procedure get_some_stuffs
@max_records int = null
as
begin
set NOCOUNT on
select top (@max_records) *
from my_table
order by mothers_maiden_name
end
我希望仅在提供 @max_records
时限制所选记录的数量。
问题:
真正的查询令人讨厌且大;我想避免重复类似于此:
if(@max_records is null)
begin
select *
from {massive query}
end
else
begin
select top (@max_records)
from {massive query}
end
任意哨兵值感觉不对:
select top (ISNULL(@max_records, 2147483647)) *
from {massive query}
例如,如果@max_records
为null
且{massive query}
返回的行数少于2147483647
,则与以下内容相同:
select *
from {massive query}
或者从只有50行的表格中选择top (2147483647) *
是否会受到某种惩罚?
是否有其他现有模式允许可选的计数限制结果集而不重复查询或使用sentinel值?
答案 0 :(得分:2)
我正在考虑这个问题,虽然我喜欢IF
声明中Problem 1
语句的明确性,但我理解重复的问题。因此,您可以将主查询放在单个CTE中,并使用一些技巧从中查询(粗体部分是此解决方案的亮点):
CREATE PROC get_some_stuffs
(
@max_records int = NULL
)
AS
BEGIN
SET NOCOUNT ON;
WITH staged AS (
-- Only write the main query one time
SELECT * FROM {massive query}
)
-- This part below the main query never changes:
SELECT *
FROM (
-- A little switcheroo based on the value of @max_records
SELECT * FROM staged WHERE @max_records IS NULL
UNION ALL
SELECT TOP(ISNULL(@max_records, 0)) * FROM staged WHERE @max_records IS NOT NULL
) final
-- Can't use ORDER BY in combination with a UNION, so move it out here
ORDER BY mothers_maiden_name
END
我查看了每个的实际查询计划,优化器非常智能,完全避免了不需要运行的UNION ALL
部分。
ISNULL(@max_records, 0)
就在那里,因为TOP NULL
无效,而且无法编译。
答案 1 :(得分:1)
有一些方法,但正如你可能会注意到这些方法看起来都很难看或者是不必要的复杂。此外,你真的需要ORDER BY吗?
您可以使用TOP (100) PERCENT
和一个视图,但PERCENT仅在您不需要那么昂贵的ORDER BY
,时才有效,因为如果您将SQL Server忽略您的ORDER BY
试试吧。
我建议利用存储过程,但首先让我们解释一下procs类型的区别:
硬编码参数嗅探
--Note the lack of a real parametrized column. See notes below.
IF OBJECT_ID('[dbo].[USP_TopQuery]', 'U') IS NULL
EXECUTE('CREATE PROC dbo.USP_TopQuery AS ')
GO
ALTER PROC [dbo].[USP_TopQuery] @MaxRows NVARCHAR(50)
AS
BEGIN
DECLARE @SQL NVARCHAR(4000) = N'SELECT * FROM dbo.ThisFile'
, @Option NVARCHAR(50) = 'TOP (' + @MaxRows + ') *'
IF ISNUMERIC(@MaxRows) = 0
EXEC sp_executesql @SQL
ELSE
BEGIN
SET @SQL = REPLACE(@SQL, '*', @Option)
EXEC sp_executesql @SQL
END
END
局部变量参数嗅探
IF OBJECT_ID('[dbo].[USP_TopQuery2]', 'U') IS NULL
EXECUTE('CREATE PROC dbo.USP_TopQuery2 AS ')
GO
ALTER PROC [dbo].[USP_TopQuery2] @MaxRows INT NULL
AS
BEGIN
DECLARE @Rows INT;
SET @Rows = @MaxRows;
IF @MaxRows IS NULL
SELECT *
FROM dbo.THisFile
ELSE
SELECT TOP (@Rows) *
FROM dbo.THisFile
END
无参数嗅探,旧方法
IF OBJECT_ID('[dbo].[USP_TopQuery3]', 'U') IS NULL
EXECUTE('CREATE PROC dbo.USP_TopQuery3 AS ')
GO
ALTER PROC [dbo].[USP_TopQuery3] @MaxRows INT NULL
AS
BEGIN
IF @MaxRows IS NULL
SELECT *
FROM dbo.THisFile
ELSE
SELECT TOP (@MaxRows) *
FROM dbo.THisFile
END
请注意参数SNIFFING:
SQL Server在编译时时初始化存储过程中的变量,而不是在它解析时。
这意味着SQL Server将无法猜测查询 无论如何,请为查询选择上一个有效执行计划 是否好。
有两种方法,硬编码允许优化器猜测的局部变量。
参数嗅探的硬编码
ON
,WHERE
,HAVING
),该方法的效果如何RECOMPILE
来解决此问题。变量参数嗅探
最终,性能问题是关于哪种方法将使用最少量的步骤遍历传单。表格中的统计信息,行以及SQL Server决定使用“扫描与搜索”时的规则会影响性能。
运行不同的值会显着改变性能,但通常会优于USP_TopQuery3。所以不要假设一种方法必然比另一种更好。
如果您要回答'为避免重复代码,请使用 功能' - 请更加努力!存储过程也可以这样做......
如果你要回答 '可以在SELECT中使用函数,而存储过程则不能 使用' - 再次思考!
SQL SERVER – Question to You – When to use Function and When to use Stored Procedure
答案 2 :(得分:0)
你可以这样做(使用你的例子):
create procedure get_some_stuffs
@max_records int = null
as
begin
set NOCOUNT on
select top (ISNULL(@max_records,1000)) *
from my_table
order by mothers_maiden_name
end
我知道你不喜欢这样(根据你的观点2),但这完全取决于它是如何完成的(根据我的经验)。
答案 3 :(得分:0)
这样的事情怎么样(你必须真正看看执行计划,我没有时间设置任何东西)?
create procedure get_some_stuffs
@max_records int = null
as
begin
set NOCOUNT on
select *, ROW_NUMBER(OVER order by mothers_maiden_name) AS row_num
from {massive query}
WHERE @max_records IS NULL OR row_num < @max_records
end
使用{large query}可以做的另一件事是创建一个视图或内联表值函数(它是参数化的),对于任何大型和重复使用的函数来说,这通常都是一个很好的做法。
答案 4 :(得分:0)
您可以使用SET ROWCOUNT
:
var Rows = $find('<%= RadGrid1.ClientID %>').get_masterTableView().get_dataItems();
var Clicked_rowIndex = object.parentNode.parentNode.rowIndex;
var row = Rows[Clicked_rowIndex-1];
id = row.getDataKeyValue("id");
alert(id);