- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个包含2个计算列的表,两个列的“ Is Persisted”都设置为true。但是,在查询中使用它们时,执行计划会显示用于计算列的UDF作为计划的一部分。由于在添加/更新行时,列数据是由UDF计算的,为什么计划要包含它?
当这些列包含在查询中时,查询速度非常慢(> 30s),如果排除了这些列,则闪电般快(<1s)。这使我得出一个结论,即查询实际上是在运行时计算列值,但情况并非如此,因为它们被设置为持久化。
我在这里想念什么吗?
更新:这是有关我们使用计算列的推理的更多信息。
我们是一家体育用品公司,并且有一个客户将完整的运动员姓名存储在一个栏中。他们要求我们允许他们分别按名字和/或姓氏搜索球员数据。幸运的是,它们使用一致的格式来命名玩家的名字-LastName,FirstName(NickName)-因此解析它们相对容易。我创建了一个UDF,该UDF调用CLR函数以使用正则表达式解析名称部分。因此,显然,调用UDF(又调用CLR函数)非常昂贵。但是由于它只在一个持久化的列上使用,我认为它只会在每天将数据导入数据库的几次中使用。
最佳答案
原因是查询优化器在花费用户定义的函数方面做得不好。在某些情况下,它决定完全重新评估每一行的功能要便宜,而不是招致否则可能需要的磁盘读取。
SQL Server的成本核算模型不会检查函数的结构以查看其实际成本,因此优化器在这方面没有准确的信息。您的功能可能非常复杂,因此以这种方式限制成本是可以理解的。对于标量和多语句表值函数,效果最差,因为按行调用它们非常昂贵。
您可以通过检查查询计划来判断优化器是否已决定重新评估功能(而不是使用持久值)。如果有一个Compute Scalar迭代器在其Defined Values列表中明确引用了该函数名称,则该函数将每行调用一次。如果“定义的值”列表引用了列名,则不会调用该函数。
我的建议通常是根本不在计算列定义中使用函数。
下面的复制脚本演示了此问题。请注意,为表定义的PRIMARY KEY是非集群的,因此要获取持久值,将需要从索引中进行书签查找或进行表扫描。优化器决定从索引中读取函数的源列并按行重新计算函数会更便宜,而不是花费书签查找或表扫描的开销。
在这种情况下,索引保留的列可加快查询的速度。通常,优化器倾向于使用避免重新计算功能的访问路径,但是该决定是基于成本的,因此即使对索引进行索引,仍然有可能为每行重新计算功能。但是,为优化器提供“显而易见的”有效访问路径确实有助于避免这种情况。
请注意,不必为要建立索引而保留该列。这是一个非常普遍的误解。只有在不精确的地方(使用浮点算术或值),才需要保留列。在当前情况下保留该列不会增加任何值,并且会扩展基表的存储要求。
保罗·怀特
-- An expensive scalar function
CREATE FUNCTION dbo.fn_Expensive(@n INTEGER)
RETURNS BIGINT
WITH SCHEMABINDING
AS
BEGIN
DECLARE @sum_n BIGINT;
SET @sum_n = 0;
WHILE @n > 0
BEGIN
SET @sum_n = @sum_n + @n;
SET @n = @n - 1
END;
RETURN @sum_n;
END;
GO
-- A table that references the expensive
-- function in a PERSISTED computed column
CREATE TABLE dbo.Demo
(
n INTEGER PRIMARY KEY NONCLUSTERED,
sum_n AS dbo.fn_Expensive(n) PERSISTED
);
GO
-- Add 8000 rows to the table
-- with n from 1 to 8000 inclusive
WITH Numbers AS
(
SELECT TOP (8000)
n = ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM master.sys.columns AS C1
CROSS JOIN master.sys.columns AS C2
CROSS JOIN master.sys.columns AS C3
)
INSERT dbo.Demo (N.n)
SELECT
N.n
FROM Numbers AS N
WHERE
N.n >= 1
AND N.n <= 5000
GO
-- This is slow
-- Plan includes a Compute Scalar with:
-- [dbo].[Demo].sum_n = Scalar Operator([[dbo].[fn_Expensive]([dbo].[Demo].[n]))
-- QO estimates calling the function is cheaper than the bookmark lookup
SELECT
MAX(sum_n)
FROM dbo.Demo;
GO
-- Index the computed column
-- Notice the actual plan also calls the function for every row, and includes:
-- [dbo].[Demo].sum_n = Scalar Operator([[dbo].[fn_Expensive]([dbo].[Demo].[n]))
CREATE UNIQUE INDEX uq1 ON dbo.Demo (sum_n);
GO
-- Query now uses the index, and is fast
SELECT
MAX(sum_n)
FROM dbo.Demo;
GO
-- Drop the index
DROP INDEX uq1 ON dbo.Demo;
GO
-- Don't persist the column
ALTER TABLE dbo.Demo
ALTER COLUMN sum_n DROP PERSISTED;
GO
-- Show again, as you would expect
-- QO has no option but to call the function for each row
SELECT
MAX(sum_n)
FROM dbo.Demo;
GO
-- Index the non-persisted column
CREATE UNIQUE INDEX uq1 ON dbo.Demo (sum_n);
GO
-- Fast again
-- Persisting the column bought us nothing
-- and used extra space in the table
SELECT
MAX(sum_n)
FROM dbo.Demo;
GO
-- Clean up
DROP TABLE dbo.Demo;
DROP FUNCTION dbo.fn_Expensive;
GO
关于performance - 为什么执行计划包括对持久化的计算列的用户定义函数调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5998217/
我正在 csv 上使用 hadoop 来分析一些数据。我使用sql/mysql(不确定)来分析数据,现在陷入了僵局。 我花了好几个小时在谷歌上搜索,却没有找到任何相关的东西。我需要一个查询,在该查询中
我正在为 Bootstrap 网格布局的“简单”任务而苦苦挣扎。我希望在大视口(viewport)上有 4 列,然后在中型设备上有 2 列,最后在较小的设备上只有 1 列。 当我测试我的代码片段时,似
对于这个令人困惑的标题,我深表歉意,我想不出这个问题的正确措辞。相反,我只会给你背景信息和目标: 这是在一个表中,一个人可能有也可能没有多行数据,这些行可能包含相同的 activity_id 值,也可
具有 3 列的数据库表 - A int , B int , C int 我的问题是: 如何使用 Sequelize 结果找到 A > B + C const countTasks = await Ta
我在通过以下功能编写此查询时遇到问题: 首先按第 2 列 DESC 排序,然后从“不同的第 1 列”中选择 只有 Column1 是 DISTINCT 此查询没有帮助,因为它首先从第 1 列中进行选择
使用 Bootstrap 非常有趣和有帮助,目前我在创建以下需求时遇到问题。 “使用 bootstrap 在桌面上有 4 列,在平板电脑上有 2 列,在移动设备上有 1 列”谁能告诉我正确的结构 最佳
我是 R 新手,正在问一个非常基本的问题。当然,我在尝试从所提供的示例中获取指导的同时做了功课here和 here ,但无法在我的案例中实现这个想法,即可能是由于我的问题中的比较维度更大。 我的实
通常我会使用 R 并执行 merge.by,但这个文件似乎太大了,部门中的任何一台计算机都无法处理它! (任何从事遗传学工作的人的附加信息)本质上,插补似乎删除了 snp ID 的 rs 数字,我只剩
我有一个 df , delta1 delta2 0 -1 2 0 -1 0 0 0 我想知道如何分配 delt
您好,我想知道是否可以执行以下操作。显然,我已经尝试在 phpMyAdmin 中运行它,但出现错误。也许还有另一种方式来编写此查询。 SELECT * FROM eat_eat_restaurants
我有 2 个列表(标题和数据值)。我想要将数据值列 1 匹配并替换为头文件列 1,以获得与 dataValue 列 1 和标题值列 2 匹配的值 头文件 TotalLoad,M0001001 Hois
我有两个不同长度的文件,file2 是一个很大的引用文件,我从中提取文件 1 的数据。 我有一行 awk,我通常会对其进行调整以在我的文件中进行查找和替换,但它总是在同一列中进行查找和替换。 所以对于
假设我有两个表,如下所示。 create table contract( c_ID number(1) primary key, c_name varchar2(50) not
我有一个带有 varchar 列的 H2 表,其检查约束定义如下: CONSTRAINT my_constraint CHECK (varchar_field <> '') 以下插入语句失败,但当我删
这是最少量的代码,可以清楚地说明我的问题: One Two Three 前 2 个 div 应该是 2 个左列。第三个应该占据页面的其余部分。最后,我将添加选项来隐藏和
在 Azure 中的 Log Analytics 中,我为 VM Heartbeat 选择一个预定义查询,我在编辑器中运行查询正常,但当我去创建警报时,我不断收到警报“查询未返回 TimeGenera
在 Azure 中的 Log Analytics 中,我为 VM Heartbeat 选择一个预定义查询,我在编辑器中运行查询正常,但当我去创建警报时,我不断收到警报“查询未返回 TimeGenera
今天我开始使用 JexcelApi 并遇到了这个:当您尝试从特定位置获取元素时,不是像您通常期望的那样使用sheet.getCell(row,col),而是使用sheet.getCell(col,ro
我有一个包含 28 列的数据库。第一列是代码,第二列是名称,其余是值。 public void displayData() { con.Open(); MySqlDataAdapter
我很沮丧:每当我缩小这个网页时,一切都变得一团糟。我如何将网页居中,以便我可以缩小并且元素不会被错误定位。 (它应该是 2 列,但所有内容都合并为 1)我试过 但由于某种原因,这不起作用。 www.o
我是一名优秀的程序员,十分优秀!