DBA*_*rew 16 sql t-sql sql-server sql-server-2005 sql-function
为什么标量值函数似乎会导致查询在连续使用它们的次数越多,累积运行速度越慢?
我有这个表是用从第三方购买的数据构建的.
我已经删除了一些东西,以使这篇文章缩短...但只是让你了解事情是如何设置的.
CREATE TABLE [dbo].[GIS_Location](
[ID] [int] IDENTITY(1,1) NOT NULL, --PK
[Lat] [int] NOT NULL,
[Lon] [int] NOT NULL,
[Postal_Code] [varchar](7) NOT NULL,
[State] [char](2) NOT NULL,
[City] [varchar](30) NOT NULL,
[Country] [char](3) NOT NULL,
CREATE TABLE [dbo].[Address_Location](
[ID] [int] IDENTITY(1,1) NOT NULL, --PK
[Address_Type_ID] [int] NULL,
[Location] [varchar](100) NOT NULL,
[State] [char](2) NOT NULL,
[City] [varchar](30) NOT NULL,
[Postal_Code] [varchar](10) NOT NULL,
[Postal_Extension] [varchar](10) NULL,
[Country_Code] [varchar](10) NULL,
Run Code Online (Sandbox Code Playgroud)
然后我有两个查找LAT和LON的函数.
CREATE FUNCTION [dbo].[usf_GIS_GET_LAT]
(
@City VARCHAR(30),
@State CHAR(2)
)
RETURNS INT
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @LAT INT
SET @LAT = (SELECT TOP 1 LAT FROM GIS_Location WITH(NOLOCK) WHERE [State] = @State AND [City] = @City)
RETURN @LAT
END
CREATE FUNCTION [dbo].[usf_GIS_GET_LON]
(
@City VARCHAR(30),
@State CHAR(2)
)
RETURNS INT
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @LON INT
SET @LON = (SELECT TOP 1 LON FROM GIS_Location WITH(NOLOCK) WHERE [State] = @State AND [City] = @City)
RETURN @LON
END
Run Code Online (Sandbox Code Playgroud)
当我运行以下...
SET STATISTICS TIME ON
SELECT
dbo.usf_GIS_GET_LAT(City,[State]) AS Lat,
dbo.usf_GIS_GET_LON(City,[State]) AS Lon
FROM
Address_Location WITH(NOLOCK)
WHERE
ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)
SET STATISTICS TIME OFF
Run Code Online (Sandbox Code Playgroud)
100~ = 8 ms,200~ = 32 ms,400~ = 876 ms
- 编辑对不起我应该更清楚了.我不打算调整上面列出的查询.这只是一个示例,显示执行时间越慢,它所经历的记录就越多.在现实世界的应用程序中,函数被用作where子句的一部分,用于在城市和州周围建立半径以包括该区域中的所有记录.
Joh*_*ibb 28
在大多数情况下,最好避免使用引用表的标量值函数,因为(正如其他人所说)它们基本上是需要为每一行运行一次的黑盒子,并且无法通过查询计划引擎进行优化.因此,即使关联表具有索引,它们也倾向于线性扩展.
您可能需要考虑使用内联表值函数,因为它们是与查询内联求值的,并且可以进行优化.您可以获得所需的封装,但是在select语句中粘贴表达式的性能.
作为内联的副作用,它们不能包含任何过程代码(没有声明@variable;设置@variable = ..; return).但是,它们可以返回多个行和列.
您可以重写这样的函数:
create function usf_GIS_GET_LAT(
@City varchar (30),
@State char (2)
)
returns table
as return (
select top 1 lat
from GIS_Location with (nolock)
where [State] = @State
and [City] = @City
);
GO
create function usf_GIS_GET_LON (
@City varchar (30),
@State char (2)
)
returns table
as return (
select top 1 LON
from GIS_Location with (nolock)
where [State] = @State
and [City] = @City
);
Run Code Online (Sandbox Code Playgroud)
使用它们的语法也有一点不同:
select
Lat.Lat,
Lon.Lon
from
Address_Location with (nolock)
cross apply dbo.usf_GIS_GET_LAT(City,[State]) AS Lat
cross apply dbo.usf_GIS_GET_LON(City,[State]) AS Lon
WHERE
ID IN (SELECT TOP 100 ID FROM Address_Location WITH(NOLOCK) ORDER BY ID DESC)
Run Code Online (Sandbox Code Playgroud)
他们不.
标量函数中没有任何错误导致其性能以指数方式降级,具体取决于执行标量函数中的行数.再次尝试测试并查看SQL事件探查器,查看CPU和READS和DURATION列.增加测试大小以包括花费超过一秒,两秒,五秒的测试.
CREATE FUNCTION dbo.slow
(
@ignore int
)
RETURNS INT
AS
BEGIN
DECLARE @slow INT
SET @slow = (select count(*) from sysobjects a
cross join sysobjects b
cross join sysobjects c
cross join sysobjects d
cross join sysobjects e
cross join sysobjects f
where a.id = @ignore)
RETURN @slow
END
go
SET STATISTICS TIME ON
select top 1 dbo.slow(id)
from sysobjects
go
select top 5 dbo.slow(id)
from sysobjects
go
select top 10 dbo.slow(id)
from sysobjects
go
select top 20 dbo.slow(id)
from sysobjects
go
select top 40 dbo.slow(id)
from sysobjects
SET STATISTICS TIME OFF
Run Code Online (Sandbox Code Playgroud)
产量
SQL Server Execution Times:
CPU time = 203 ms, elapsed time = 202 ms.
SQL Server Execution Times:
CPU time = 889 ms, elapsed time = 939 ms.
SQL Server Execution Times:
CPU time = 1748 ms, elapsed time = 1855 ms.
SQL Server Execution Times:
CPU time = 3541 ms, elapsed time = 3696 ms.
SQL Server Execution Times:
CPU time = 7207 ms, elapsed time = 7392 ms.
Run Code Online (Sandbox Code Playgroud)
请记住,如果对结果集中的行运行标量函数,则标量函数将按行执行,不进行全局优化.
归档时间: |
|
查看次数: |
40835 次 |
最近记录: |