Sql server 它将从表中提取数据(这就是为什么过时的静态数据也会严重影响性能)。所以当您使用标量函数或mTVF时,优化器无法像使用内联代码那样评估所有需求。它的响应是简单地假设函数只执行一次,并根据该假设制定计划

Sql server 它将从表中提取数据(这就是为什么过时的静态数据也会严重影响性能)。所以当您使用标量函数或mTVF时,优化器无法像使用内联代码那样评估所有需求。它的响应是简单地假设函数只执行一次,并根据该假设制定计划,sql-server,stored-procedures,user-defined-functions,user-defined-types,Sql Server,Stored Procedures,User Defined Functions,User Defined Types,由于假设是错误的,因此产生了错误的计划,最终导致糟糕的绩效 解决方法是重写有问题的函数。。。关键是#1,确保将它们重写为“内联表值函数”(iTVF)。优化器只会看到这些函数,就好像它们的代码是直接输入到外部查询中一样(因此称为“内联”)。如果您不熟悉iTVFs,他们有两个要求。。。1它们必须是表函数(无论出于何种原因,MS仍然没有提供标量版本)。。。而且。。。这是最重要的。。。函数体必须是单个语句 那么,如果不需要表值函数,需要标量函数呢?没有什么能说明多值函数不能返回单个(标量)值。。。这就是

由于假设是错误的,因此产生了错误的计划,最终导致糟糕的绩效

解决方法是重写有问题的函数。。。关键是#1,确保将它们重写为“内联表值函数”(iTVF)。优化器只会看到这些函数,就好像它们的代码是直接输入到外部查询中一样(因此称为“内联”)。如果您不熟悉iTVFs,他们有两个要求。。。1它们必须是表函数(无论出于何种原因,MS仍然没有提供标量版本)。。。而且。。。这是最重要的。。。函数体必须是单个语句

那么,如果不需要表值函数,需要标量函数呢?没有什么能说明多值函数不能返回单个(标量)值。。。这就是为什么那些知道情况的人把他们所有的功能都编码为iTVFs

好的方面是,web上不缺少关于创建“内联标量函数”的信息,使用编码为在web上返回标量值的表函数


希望这有帮助…

正如您在问题中提到的,标量函数和多语句表值函数(mTVF)对于优化器来说都是“黑盒”

所以,我的问题是,“为什么这么糟糕?”。答案是,为了提出一个尽可能高效执行的好计划,它需要了解特定需求的某些细节以及它将从中提取数据的表的信息(这就是为什么过时的静态也会严重影响性能)。所以当您使用标量函数或mTVF时,优化器无法像使用内联代码那样评估所有需求。它的响应是简单地假设函数只执行一次,并根据该假设制定计划

由于假设是错误的,因此产生了错误的计划,最终导致糟糕的绩效

解决方法是重写有问题的函数。。。关键是#1,确保将它们重写为“内联表值函数”(iTVF)。优化器只会看到这些函数,就好像它们的代码是直接输入到外部查询中一样(因此称为“内联”)。如果您不熟悉iTVFs,他们有两个要求。。。1它们必须是表函数(无论出于何种原因,MS仍然没有提供标量版本)。。。而且。。。这是最重要的。。。函数体必须是单个语句

那么,如果不需要表值函数,需要标量函数呢?没有什么能说明多值函数不能返回单个(标量)值。。。这就是为什么那些知道情况的人把他们所有的功能都编码为iTVFs

好的方面是,web上不缺少关于创建“内联标量函数”的信息,使用编码为在web上返回标量值的表函数


希望这有帮助…

使用连接而不是“IN”子句帮助很大。(虽然我也将表var改为临时表,这也有很大帮助。)

使用连接而不是“IN”子句帮助很大。(虽然我也将表变量更改为临时表,这也有很大帮助。)

这太模糊了,您的自定义项可以是标量函数或表值,也可以是单语句或多语句,您可以将它们用作相关子查询或针对它们进行连接。这一清单不胜枚举。您需要给出一个与您的特定情况相关的实际示例,也许在阅读本文之后?(获取两个版本代码的执行计划,看看它们有什么不同,这也不是一个坏主意,这可能会帮助您找出它们不同的原因)对于任何读者来说,我尝试添加选项(重新编译),但这没有什么不同。还尝试在.Net(webserver)中创建SQL查询并直接运行,但事实证明,这比使用函数或存储过程更慢。如果使用UDT运行该查询,但不使用函数包装,会发生什么情况?这将帮助您隔离导致性能问题的更改(在函数中添加UDT或包装)。我怀疑这就是UDT的问题所在。如果是这样,请尝试重写查询以加入游戏,而不是在()中使用
,或将索引和统计信息应用于UDT。这太模糊了,您的UDF可能是标量函数或表值,可能是单语句或多语句,您可以将它们用作相关子查询或针对它们进行连接。这一清单不胜枚举。您需要给出一个与您的特定情况相关的实际示例,也许在阅读本文之后?(获取两个版本代码的执行计划,看看它们有什么不同,这也不是一个坏主意,这可能会帮助您找出它们不同的原因)对于任何读者来说,我尝试添加选项(重新编译),但这没有什么不同。还尝试在.Net(webserver)中创建SQL查询并直接运行,但事实证明,这比使用函数或存储过程更慢。如果使用UDT运行该查询,但不使用函数包装,会发生什么情况?这将帮助您隔离导致性能问题的更改(在函数中添加UDT或包装)。我怀疑这就是UDT的问题所在。如果是这样,请尝试重写查询以加入游戏,而不是在()中使用
,或应用索引和统计信息
SELECT
SelectedContracts.MeasurableID,
SelectedContracts.EntityID,

EntityName,
EntityAbbrev,
EntityLogoURL,
EntityHex1,
EntityHex2,
EntitySportID,

MeasurableName,
MeasurableOrganizationID,
YearFilter,
SeasonFilter,
CategoryFilter,
ResultFilter,
Logo4Result,
MeasurableSportID,
MouseoverFooter,
ContractRank4Org,
ContractEndUTC,

HighContractPrice4Period,
HighTradeID,
HighTradeUTC,
HighTradeNumberOfContracts,
HighTradeCurrency,

LowContractPrice4Period,
LowTradeID,
LowTradeUTC,
LowTradeNumberOfContracts,
LowTradeCurrency,

LastTradePrice,
LastTradeID,
LastTradeUTC,
LastTradeNumberOfContracts,
LastTradeCurrency,

SecondLastTradePrice,
SecondLastTradeID,
SecondLastTradeUTC,
SecondLastTradeNumberOfContracts,
SecondLastTradeCurrency,

ContractPrice4ChangeCalc,
ContractID4ChangeCalc,
ContractUTC4ChangeCalc,
ContractsNumberTraded4ChangeCalc,
ContractCurrency4ChangeCalc,

HighestBidID,
HighestBidMemberID,
HighestBidPrice,
HighestBidAvailableContracts,
HighestBidCurrency,

LowestAskID,
LowestAskMemberID,
LowestAskPrice,
LowestAskAvailableContracts,
LowestAskCurrency


FROM
(
    SELECT
        dbo.Contracts.MeasurableID,
        dbo.Contracts.EntityID
    FROM
        dbo.Contracts
    WHERE
        dbo.Contracts.MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
    GROUP BY
        dbo.Contracts.MeasurableID,
        dbo.Contracts.EntityID
) SelectedContracts


INNER JOIN 
(
    SELECT
        dbo.Entities.ID,
        --dbo.Entities.OrganizationID, -- Get OrganizationID from Measurable since some Entities (European soccer teams) have multiple Orgs
        dbo.Entities.EntityName,
        dbo.Entities.EntityAbbrev,
        dbo.Entities.logoURL AS EntityLogoURL,
        dbo.Entities.Hex1 AS EntityHex1,
        dbo.Entities.Hex2 AS EntityHex2,
        dbo.Entities.SportID AS EntitySportID
    FROM
        dbo.Entities
) SelectedEntities ON SelectedContracts.EntityID = SelectedEntities.ID


INNER JOIN 
(
    SELECT
        dbo.Measurables.ID AS MeasurableID,
        dbo.Measurables.Name AS MeasurableName,
        dbo.Measurables.OrganizationID AS MeasurableOrganizationID,
        dbo.Measurables.[Year] AS YearFilter,
        dbo.Measurables.Season AS SeasonFilter,
        dbo.Measurables.Category AS CategoryFilter,
        dbo.Measurables.Result AS ResultFilter,
        dbo.Measurables.Logo4Result,
        dbo.Measurables.SportID AS MeasurableSportID,
        dbo.Measurables.MouseoverFooter,
        dbo.Measurables.ContractRank4Org,
        dbo.Measurables.EndUTC AS ContractEndUTC
    FROM
        dbo.Measurables
) MEASURABLES_table ON SelectedContracts.MeasurableID = MEASURABLES_table.MeasurableID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ContractPrice AS HighContractPrice4Period,
        ID AS HighTradeID,
        UTCMatched AS HighTradeUTC,
        NumberOfContracts AS HighTradeNumberOfContracts,
        CurrencyCode AS HighTradeCurrency
    FROM
                (
                    SELECT
                        *, ROW_NUMBER () OVER (
                            PARTITION BY MeasurableID,
                            EntityID
                        ORDER BY
                            ContractPrice DESC,
                            ID DESC
                        ) RowNumber -- ID DESC means most recent trade of ties
                    FROM
                        Contracts
                    WHERE
                        MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
                        AND dbo.Contracts.UTCmatched < DATEADD(DAY, -30, SYSDATETIME())
                        AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                                )   
                ) AS InnerSelect4HighTrade

    WHERE   
        InnerSelect4HighTrade.RowNumber = 1

) HighTrades ON SelectedContracts.MeasurableID = HighTrades.MeasurableID AND SelectedContracts.EntityID = HighTrades.EntityID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ContractPrice AS LowContractPrice4Period,
        ID AS LowTradeID,
        UTCMatched AS LowTradeUTC,
        NumberOfContracts AS LowTradeNumberOfContracts,
        CurrencyCode AS LowTradeCurrency
    FROM
        (
            SELECT
                    *, ROW_NUMBER () OVER (
                    PARTITION BY MeasurableID,
                    EntityID
                ORDER BY
                    ContractPrice ASC,
                    ID DESC
                ) RowNumber -- ID DESC means most recent trade of ties
            FROM
                Contracts
            WHERE
                MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
                AND dbo.Contracts.UTCmatched < DATEADD(DAY, -30, SYSDATETIME())
                AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                        )           
        ) AS InnerSelect4LowTrade

    WHERE       InnerSelect4LowTrade.RowNumber = 1

) LowTrades ON SelectedContracts.MeasurableID = LowTrades.MeasurableID AND SelectedContracts.EntityID = LowTrades.EntityID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ContractPrice AS LastTradePrice,
        ID AS LastTradeID,
        UTCMatched AS LastTradeUTC,
        NumberOfContracts AS LastTradeNumberOfContracts,
        CurrencyCode AS LastTradeCurrency
    FROM
        (
            SELECT
                *, ROW_NUMBER () OVER (
                    PARTITION BY MeasurableID,
                    EntityID
                ORDER BY
                    ID DESC
                ) RowNumber -- ID DESC means most recent trade of ties
            FROM
                Contracts
            WHERE
                MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
                AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                        )   
        ) AS InnerSelect4LastTrade

    WHERE   InnerSelect4LastTrade.RowNumber = 1

) LastTrades ON SelectedContracts.MeasurableID = LastTrades.MeasurableID AND SelectedContracts.EntityID = LastTrades.EntityID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ContractPrice AS SecondLastTradePrice,
        ID AS SecondLastTradeID,
        UTCMatched AS SecondLastTradeUTC,
        NumberOfContracts AS SecondLastTradeNumberOfContracts,
        CurrencyCode AS SecondLastTradeCurrency
    FROM
        (
            SELECT
                *, ROW_NUMBER () OVER (
                    PARTITION BY MeasurableID,
                    EntityID
                ORDER BY
                    ID DESC
                ) RowNumber -- ID DESC means most recent trade of ties
            FROM
                Contracts
            WHERE
                MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
                AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                        )   
--need time filter???
        ) AS InnerSelect4SecondToLastTrade

    WHERE InnerSelect4SecondToLastTrade.RowNumber = 2

) SecondToLastTrade ON SelectedContracts.MeasurableID = SecondToLastTrade.MeasurableID AND SelectedContracts.EntityID = SecondToLastTrade.EntityID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ContractPrice AS ContractPrice4ChangeCalc,
        ID AS ContractID4ChangeCalc,
        UTCMatched AS ContractUTC4ChangeCalc,
        NumberOfContracts AS ContractsNumberTraded4ChangeCalc,
        CurrencyCode AS ContractCurrency4ChangeCalc
    FROM
        (
            SELECT
                *, ROW_NUMBER () OVER (
                    PARTITION BY MeasurableID,
                    EntityID
                ORDER BY
                    ID DESC  -- ID DESC equals the most recent trade if ties
                ) RowNumber 
            FROM
                Contracts
            WHERE
                MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
                AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                        )   
            AND dbo.Contracts.UTCmatched < DATEADD(Day ,-30, SYSDATETIME())
        ) AS InnerSelect4ChangeCalcPerPeriod

    WHERE   InnerSelect4ChangeCalcPerPeriod.RowNumber = 1

) Trade4ChangeCalcPerPeriod ON SelectedContracts.MeasurableID = Trade4ChangeCalcPerPeriod.MeasurableID AND SelectedContracts.EntityID = Trade4ChangeCalcPerPeriod.EntityID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ID AS HighestBidID,
        MemberID AS HighestBidMemberID,
        BidPrice AS HighestBidPrice,
        AvailableContracts AS HighestBidAvailableContracts,
        CurrencyCode AS HighestBidCurrency
    FROM
        (
            SELECT
                *, ROW_NUMBER () OVER (
                    PARTITION BY MeasurableID,
                    EntityID
                ORDER BY
                    BidPrice DESC,
                    ID DESC
                ) RowNumber
            FROM
                dbo.Interest2Buy
            WHERE
                MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
            AND AvailableContracts > 0
                AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                        )   
        ) AS InnerSelect4HighestBid

    WHERE   InnerSelect4HighestBid.RowNumber = 1

) HighestBids ON SelectedContracts.MeasurableID = HighestBids.MeasurableID AND SelectedContracts.EntityID = HighestBids.EntityID


LEFT JOIN 
(
    SELECT
        MeasurableID,
        EntityID,
        ID AS LowestAskID,
        MemberID AS LowestAskMemberID,
        AskPrice AS LowestAskPrice,
        AvailableContracts AS LowestAskAvailableContracts,
        CurrencyCode AS LowestAskCurrency
    FROM
        (
            SELECT
                *, ROW_NUMBER () OVER (
                    PARTITION BY MeasurableID,
                    EntityID
                ORDER BY
                    AskPrice ASC,
                    ID DESC
                ) RowNumber
            FROM
                dbo.Interest2Sell
            WHERE
                MeasurableID IN ((2030),(2017),(2018),(2019),(2020),( 2028),(2024),(2027),(2029),(2022),( 4018),(4019),(4020),(4021))
                AND AvailableContracts > 0
                AND (           CurrencyCode IN (('GBP'), ('CAD'), ('INR'), ('BRL'), ('MXN'), ('CHF'), ('RUB')) 
                        )   
        ) AS InnerSelect4BestAsk

    WHERE   InnerSelect4BestAsk.RowNumber = 1

) BestAsks ON SelectedContracts.MeasurableID = BestAsks.MeasurableID AND SelectedContracts.EntityID = BestAsks.EntityID