我有一个包含大量 UDF 的数据库,这些 UDF 由涉及大量数据操作和计算的长时间运行的进程调用。
我使用 UDF 的想法是将信息的逻辑单元从底层表中分离出来。例如,如果我想获取有关汽车的信息,我可能有几个表,例如颜色、型号、年份等,每次获取汽车时我都必须加入这些表。相反,我将使用像 fnCar() 这样的函数来获取数据的非规范化视图。
我在长时间运行的过程中多次调用这些函数,我想知道如果我有一个非规范化的工作表、视图或临时表来进行数据操作和计算是否会更好。一般来说,使用 UDF 在性能方面是否有一些我应该注意的缺点?
例如,我使用 UDF 进行一些计算。然后,我对该数据进行逆透视并将其存储在表中。每当我需要再次使用该数据时,我都会调用 UDF 将数据转回原处。我们这样做的原因是为了保持计算的灵活性。如果我们添加/删除/更改计算,我们不想更改数据模型。
--Calculate some values in a function
declare @location table
(
id int,
lattitude float,
longitude float
)
insert into @location select 1, 40.7, 74
insert into @location select 2, 42, 73
insert into @location select 3, 61, 149
insert into @location select 4, 41, 87
declare @myLattitude float
declare @myLongitude float
set @myLattitude =43
set @myLongitude = 116
declare @distance table
( …Run Code Online (Sandbox Code Playgroud) 最近,我正在解决一个奇怪的性能问题,该问题影响了应用程序的生产环境,但不影响任何较低的环境。我设法用这个查询以最简单的形式复制了这个问题:
SELECT product_id, dbo.TranslateStatusToActive(status_id) FROM prod_Products
Run Code Online (Sandbox Code Playgroud)
TranslateStatusToActive是一个非常简单的标量 UDF,它基本上只是连接给另一个表的值,并根据case语句返回 1 或 0 。我会发布代码,但它是供应商编写的功能,我今天对被起诉并不特别感兴趣。(是的,逻辑可以内联。是的,它解决了性能问题。是的,我们已经说服供应商实施更改。这不是我的问题。)
在生产中执行时,查询需要 10 到 20 秒才能返回结果。在开发中,相同的查询在不到 3 秒的时间内返回。执行计划几乎相同,除了显示 CPU 时间在生产中约为 15000 毫秒,其他地方为 3000 毫秒。
我怀疑存在一些环境差异,因此我设置了另一台服务器来尽可能地复制生产条件:我确保 CPU 的数量、分配给 SQL Server 的内存量以及特定的补丁级别 (13.0.0.1)。 4451) 相同。
我将生产数据库的副本恢复到这个新的沙箱服务器,令我惊讶的是,查询的执行速度与它在开发中的执行速度一样快。再一次,计划和数据是相同的,除了额外的 CPU 时间。执行计划中列出的等待类型相同,并且在每个环境中彼此相差几毫秒。
不知道接下来要做什么,我optimize for ad hoc workloads在生产服务器上启用了。这解决了性能问题!但是有一件事:其他环境都没有启用此设置。我一直在测试期间定期清除每个环境中的程序和系统缓存,所以我认为这不是更改设置导致重新编译的结果。
optimize for ad hoc workloads启用生产环境才能与未启用它的其他环境一样好?开发是共享的,而生产目前仅由该应用程序使用。第三个盒子的用法和生产的盒子几乎一样。我几乎清除了他们发出DBCC命令的每个缓存。开发环境经常用作培训系统,所以我相当确信这不是计划缓存问题。
与第三个框的唯一区别是没有连接到它的应用程序,但是在我在生产中测试该功能时几乎没有使用应用程序,所以区别在于,基于我在这种环境中工作的经验,微不足道。我唯一不能做的就是重启生产服务器,但微软的文档明确指出启用optimize for ad hoc workloads不会清除或影响任何现有计划,所以我看不出有什么区别。
performance sql-server functions sql-server-2016 query-performance
我正在尝试为我的公司优化汇总代码,但遇到了一个非常奇怪的问题。我将许多标量函数转换为 TVF,它们似乎都比原始函数运行得更快,这很棒。但是,在调用它们的查询中,它们最终的运行速度明显慢于原始查询。这是我的更新的基本概述:
SELECT col1, ..., colx,
(CASE WHEN x <= 0 OR y <= 0 OR z <= 0 OR z = x
THEN output
WHEN valX <= 0
THEN output
WHEN minimum.min < 1.0 THEN 1.0
ELSE minimum.min
END) AS Q,
FROM Tbl1...tblx (series of inner joins)
CROSS APPLY dbo.inlinemin(val1, val2) AS minimum
Run Code Online (Sandbox Code Playgroud)
这是原文的基本轮廓:
SELECT col1, ..., colx,
(CASE WHEN x <= 0 OR y <= 0 OR z <= 0 OR z = x
THEN output
WHEN valX …Run Code Online (Sandbox Code Playgroud) 我主要是一名 Java 开发人员。今天我正在写一些 postgres 函数。出于习惯,我一直尝试使用类似 Javadoc 的注释风格来描述函数参数和返回类型来记录这些函数。是否有官方或广泛支持的模式来记录 postgres 函数?
我的云提供商阻止我访问fn_LocalTimeToUTC和fn_UTCToLocalTime.
我将如何在不使用这些函数的情况下在 SQL 中手动和直接获得这两个函数提供的相同功能?
为了进一步简化,我们所有的用户都在英国。
我有这个功能get_department。函数内部有一个函数调用get_po_amount.
该get_po_amount函数不再存在,因此当我尝试创建 Main 函数时get_Department,出现错误“对象名称 get_po_amount 无效”。
有什么方法可以通过不在内部创建函数来创建该函数。
我也有同样的观点问题。在另一个视图中调用一个视图。
我创建这些函数只是为了展示一个示例,我需要在大型数据库上执行此操作。
CREATE FUNCTION [dbo].[GET_DEPARTEMNET]
(
@DEPTNO NVARCHAR(100)
)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM [dbo].[dept] WHERE DEPTNO=(SELECT [dbo].[GET_PO_AMOUNT](@DEPTNO)))
GO
Run Code Online (Sandbox Code Playgroud) 我试过这个:
create or replace function c3 (arg char(3))
returns void
language plpgsql as
$$
begin
raise notice 'Value: %', arg;
end;
$$;
Run Code Online (Sandbox Code Playgroud)
但它接受三个以上的字符:
select c3('1234');
Run Code Online (Sandbox Code Playgroud) 我有一个运行良好的 UPSERT 函数,但我批量更新和插入记录,可以修改此函数,以便我将所有记录作为数组传递给此函数,然后它将作为一个事务一次性插入/更新所有记录? 如果记录号 x 失败,它应该回滚撤消在 x 之前插入/更新的任何记录?这是我的 upsert 函数:
CREATE OR REPLACE FUNCTION save_weights(rec tbl_weightment)
RETURNS text AS
$BODY$
DECLARE
myoutput text :='Nothing has occured';
BEGIN
update tbl_weightment set
vname=rec.vname,
iquality=rec.iquality,
vhooks=rec.vhooks,
tstamp=rec.tstamp
vtare=rec.vtare,
vgross=rec.vgross
WHERE id=rec.id;
IF FOUND THEN
myoutput:= 'Record successfully updated';
RETURN myoutput;
END IF;
BEGIN
INSERT INTO tbl_weightment SELECT(rec).*;
myoutput:= 'Record successfully added';
END;
RETURN myoutput;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Run Code Online (Sandbox Code Playgroud)
这个功能可以修改成这样save_weights(rec tbl_weightment[])吗??任何帮助将不胜感激
我正在尝试传递要在NOT IN操作中使用的项目数组:
ALTER FUNCTION [dbo].[fnTEST] (@CODES VARCHAR)
RETURNS TABLE
AS
RETURN
(
SELECT
T1.CODE AS 'CODE',
(SELECT COUNT(*)
FROM TABLE1 AS T2 WITH (NOLOCK)
WHERE T2.CODE NOT IN (@CODES)
) AS 'COUNT'
FROM TABLE1 T1 WITH (NOLOCK)
)
Run Code Online (Sandbox Code Playgroud)
然后我这样称呼它:
SELECT * FROM fnTEST ('500,250,202,900,204,200,300,400,600,800')
Run Code Online (Sandbox Code Playgroud)
那行不通。如果我尝试在没有引号的情况下调用它,则会收到参数过多的错误(这是预期的)。
有解决方案吗?
在计算两个日期之间的差异作为天数时,通过使用 MySQL Datediff() 函数,我遇到了一些问题,下面给出了 SQL 代码。
select datediff((select curdate()),
(select Company.CreatedOn
from
dbname.company
inner join
dbname.user
on
user.company_id = company.company_id
))
Run Code Online (Sandbox Code Playgroud)
我得到的结果如下,
Error Code: 1242 Subquery returns more than 1 row
Run Code Online (Sandbox Code Playgroud)
我确实理解错误,但我不能使用任何 id 指出如下,
select datediff
(
(select curdate()),
(select Company.CreatedOn
from
dbname.company
inner join
dbname.user
on
user.company_id = company.company_id
where
company.company_id = 17)
);
Run Code Online (Sandbox Code Playgroud)
当我运行这个查询时,我得到如下输出,
38
Run Code Online (Sandbox Code Playgroud)
我需要根据注册时间存在超过 365 天的公司来选择用户。
需要显示所有注册时间超过365天的公司,我在代码中没有提到这个条件,
我需要解决子查询结果,datediff 函数应该与所有公司 CreatedOn 值进行比较,结果只存在超过 365 天的公司。
任何帮助将不胜感激。
functions ×10
sql-server ×5
postgresql ×3
t-sql ×2
array ×1
date ×1
errors ×1
mysql ×1
optimization ×1
performance ×1
plpgsql ×1
upsert ×1