Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
若WHERE子句中使用了函数,则Sql查询时间从1秒跳到1分钟以上_Sql_Sql Server 2008 - Fatal编程技术网

若WHERE子句中使用了函数,则Sql查询时间从1秒跳到1分钟以上

若WHERE子句中使用了函数,则Sql查询时间从1秒跳到1分钟以上,sql,sql-server-2008,Sql,Sql Server 2008,我在MS SQL中有这样一个查询,它的行为非常奇怪(至少从我的角度来看) 我有一个用户定义的函数,名为:dbo.NajblizszaDataWyceny(3,'2010-02-05'),它可以简单地检查一个表中的前1个条目,并将其他几个条目连接起来。查询本身需要几毫秒,所以这不是一个大问题,但我还是显示了函数 CREATE FUNCTION [dbo].[NajblizszaDataWyceny] (@idPortfela INT, @dataWaluty DATETIME) RETURNS D

我在MS SQL中有这样一个查询,它的行为非常奇怪(至少从我的角度来看)

我有一个用户定义的函数,名为:dbo.NajblizszaDataWyceny(3,'2010-02-05'),它可以简单地检查一个表中的前1个条目,并将其他几个条目连接起来。查询本身需要几毫秒,所以这不是一个大问题,但我还是显示了函数

CREATE FUNCTION [dbo].[NajblizszaDataWyceny] (@idPortfela INT, @dataWaluty DATETIME)
RETURNS DATETIME
AS BEGIN
RETURN (

SELECT TOP 1         [WycenaData]
FROM    [BazaZarzadzanie].[dbo].[Wycena] t1
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfeleKonta] t3
    ON t1.[KlienciPortfeleKontaID] = t3.[KlienciPortfeleKontaID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfele] t4
    ON t3.[PortfelID] = t4.[PortfelID]
WHERE   [WycenaData] <= @dataWaluty  AND [t3].[PortfelID] = @idPortfela
ORDER BY [WycenaData] DESC)
END
运行需要1秒。但当我将用户函数直接放在WHERE中时,它看起来像:

SELECT  t1.[KlienciPortfeleKontaID],
    t4.[PortfelIdentyfikator] AS 'UmowaNr',
    t5.[KlienciRachunkiNumer],
    [WycenaData],
    t2.[InISIN] AS 'InstrumentISIN',
    t2.[InNazwa] AS 'InstrumentNazwa',
    [WycenaWartosc]
FROM    [BazaZarzadzanie].[dbo].[Wycena] t1
    LEFT JOIN [BazaZarzadzanie].[dbo].[Instrumenty] t2
    ON t1.[InID] = t2.[InID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfeleKonta] t3
    ON t1.[KlienciPortfeleKontaID] = t3.[KlienciPortfeleKontaID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfele] t4
    ON t3.[PortfelID] = t4.[PortfelID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciRachunki] t5
    ON t3.[KlienciRachunkiID] = t5.[KlienciRachunkiID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[WycenaTyp] t6
    ON t1.[WycenaTyp] = t6.[WycenaTyp]
WHERE   WycenaData = dbo.NajblizszaDataWyceny(3, '2010-02-05')      AND t3.[PortfelID] = 3
ORDER BY t5.[KlienciRachunkiNumer],
    WycenaData

完成需要1.5分钟。有人能解释为什么会这样吗

在第二个代码示例中,为生成的联接表中的每一行调用该函数。其中会有很多


在第一种情况下,它只被调用一次。

函数在SQL Server中不被假定为纯函数,这意味着查询优化程序不会缓存函数的结果并重新使用它;每次引用该函数时都会调用它。这甚至适用于只返回数字的简单函数(正如我们在一个项目中发现的那样,在该项目中,我们使用函数模拟常量…)

因此,在第一个版本中,调用函数时只调用一次,然后手动缓存结果并在查询中重新使用。但是在第二个版本中,当
WHERE
子句尝试匹配行时,将为每一行调用该函数。如果您有很多行,那么每行数毫秒的总和就开始增加


(也请注意,你的查询在语义上是不同的)。在第一个查询中,你说“事情与我在开始时评估的函数的结果相同”,而在第二个查询中,你在说“当我考虑行的时候,我在这个特定的实例中评估的函数的结果是相同的。”。由于您的函数使用

SELECT
语句,因此,根据事务隔离级别,如果基础数据发生更改,它可能会为不同的行返回不同的结果。)

数据库服务器显然不够聪明,无法决定只对函数求值一次,然后将其用作索引中的常数

这是MS SQL的旧版本吗

此外,如果MS-SQL有这样一个选项,您可能需要以某种方式将函数声明为确定性(为相同的输入返回相同的值)


更新:刚刚看到您的函数“只是简单地检查一个表中的前1个条目,然后再加上几个其他条目。”这意味着该函数不是确定性的,也不是独立于数据库数据的。优化器无法加快速度

除了重新调用函数外,索引也不能再使用了。这可能会产生更大的影响。谢谢,这真的解释了很多。这是MS SQL 2008,我也将在2005年运行它。
SELECT  t1.[KlienciPortfeleKontaID],
    t4.[PortfelIdentyfikator] AS 'UmowaNr',
    t5.[KlienciRachunkiNumer],
    [WycenaData],
    t2.[InISIN] AS 'InstrumentISIN',
    t2.[InNazwa] AS 'InstrumentNazwa',
    [WycenaWartosc]
FROM    [BazaZarzadzanie].[dbo].[Wycena] t1
    LEFT JOIN [BazaZarzadzanie].[dbo].[Instrumenty] t2
    ON t1.[InID] = t2.[InID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfeleKonta] t3
    ON t1.[KlienciPortfeleKontaID] = t3.[KlienciPortfeleKontaID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfele] t4
    ON t3.[PortfelID] = t4.[PortfelID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciRachunki] t5
    ON t3.[KlienciRachunkiID] = t5.[KlienciRachunkiID]
    LEFT JOIN [BazaZarzadzanie].[dbo].[WycenaTyp] t6
    ON t1.[WycenaTyp] = t6.[WycenaTyp]
WHERE   WycenaData = dbo.NajblizszaDataWyceny(3, '2010-02-05')      AND t3.[PortfelID] = 3
ORDER BY t5.[KlienciRachunkiNumer],
    WycenaData