为什么标量值函数似乎会导致查询运行速度随着连续使用次数的增加而逐渐变慢?
我有一个使用从第 3 方购买的数据构建的表。
我删除了一些内容以使这篇文章变得更短......但只是为了让您了解事情是如何设置的。
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,
然后我有两个函数来查找 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
当我运行以下命令时...
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
100 ~= 8 毫秒,200 ~= 32 毫秒,400 ~= 876 毫秒
--编辑 抱歉,我应该说得更清楚。我不想调整上面列出的查询。这只是一个示例,显示处理的记录越多,执行时间就越慢。在现实世界的应用程序中,这些函数用作 where 子句的一部分,以围绕城市和州构建半径,以包含该地区的所有记录。
最佳答案
在大多数情况下,最好避免引用表的标量值函数,因为(正如其他人所说)它们基本上是黑匣子,需要为每一行运行一次,并且不能由查询计划引擎优化。因此,即使关联表有索引,它们也倾向于线性扩展。
您可能需要考虑使用内联表值函数,因为它们是与查询一起内联计算的,并且可以进行优化。您获得了所需的封装,但获得了将表达式直接粘贴到 select 语句中的性能。
作为内联的副作用,它们不能包含任何过程代码(不声明 @variable; set @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
);
使用它们的语法也有点不同:
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)
关于sql - 为什么 SQL Server 标量值函数变得更慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/800017/