我有以下select查询,它使用标量函数来获取全名。我想通过使用变量来消除冗余,但到目前为止还没有成功。我的问题是
select
a.Id,
a.UserName,
getFullName(a.UserName),
a.CreateTime
from DataTable;
我不想两次检索'a.User'。如果我可以将a.User保存在变量中然后将其传递给函数,从而提高效率,我更愿意。
目前我想出的工作如下:
select
Id,
UserName,
getFullName(UserName),
CreateTime
from (select a.Id, a.UserName, a.CreateTime from DataTable) temp
这解决了性能问题但增加了两次写入相同选择的开销。任何其他建议都会很棒。
DataTable看起来像这样
+----+----------+------------+
| Id | UserName | CreateTime |
+----+----------+------------+
| 1 | ab | 10:00 |
| 2 | cd | 11:00 |
| 3 | ef | 12:00 |
+----+----------+------------+
以下是用于获取全名
的NamesTable+----------+----------+
| UserName | FullName |
+----------+----------+
| ab | Aa BB |
| cd | Cc Dd |
| ef | Ee Ff |
+----------+----------+
以下是获取全名的功能
Create function [dbo].[getFullName](@user varchar(150)) returns varchar(500)
as
begin
declare @Result varchar(500);
select @Result = FullName from dbo.NamesTable where UserName = @user;
return @Result;
end;
答案 0 :(得分:4)
您正在解决不存在的问题。你似乎认为
select
a.Id,
a.UserName,
getFullName(a.UserName),
a.CreateTime
from DataTable;
它背后有一些相对昂贵的过程让UserName
发生两次。实际上,一旦找到记录,获取UserName
值几乎是即时过程,因为它可能会被幕后的SQL引擎存储在“变量”中。您应该在该查询和
select
a.Id,
getFullName(a.UserName),
a.CreateTime
from DataTable;
标量函数本身可能存在性能问题,但并不是因为您“拉”UserName
值“两次”。
更好的方法是加入另一个表:
select
a.Id,
a.UserName,
b.FullName,
a.CreateTime
from DataTable a
LEFT JOIN dbo.NamesTable b
ON a.UserName = b.UserName
答案 1 :(得分:3)
正如D斯坦利所说,你正试图解决一些不存在的问题。我还要补充一点,你根本不应该使用这个功能。 SQL旨在执行基于集合的操作。当你使用这样的函数时,你现在正在使它为每一行一遍又一遍地执行相同的功能 - 这是一种可怕的做法。相反,在另一个表中只有JOIN
(基于集合的操作)并让SQL做它最擅长的事情:
SELECT
DT.Id,
DT.UserName,
NT.fullname,
DT.CreateTime
FROM
DataTable DT
INNER JOIN NamesTable NT ON NT.username = DT.username;
此外,DataTable
和NamesTable
是表格的可怕名称。当然它们是表格,所以没有必要在名称的末尾加上“表格”。当然,第一个拥有“数据”,它是一个数据库。您的表名应该是描述性的。 {strong}完全 <{1}}持有什么?
如果您将来要进行SQL开发,那么我强烈建议您阅读有关该主题的几本入门书籍,并观看尽可能多的教程视频。
答案 2 :(得分:2)
标量UDF将针对每一行执行,但不会像你想象的那样完全执行。下面是样本演示和执行计划,证明相同......
create table testid
(
id int,
name varchar(20)
)
insert into testid
select n,'abc'
from numbers
where n<=1000000
create index nci_get on dbo.testid(id,name)
select id,name,dbo.getusername(id) from dbo.testid where id>4
解码以上计划:
索引查找输出id,名称
然后计算标量尝试从现有行值计算新行。在这种情况下,expr1003是我们的函数
索引搜索成本是97%,计算标量成本是3%,并且您可能知道索引搜索不是一个运算符去表获取数据。所以希望这清除您的问题