如何在选择查询中使用变量?

时间:2016-04-26 16:58:10

标签: sql sql-server select subquery

我有以下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;

3 个答案:

答案 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;

此外,DataTableNamesTable是表格的可怕名称。当然它们是表格,所以没有必要在名称的末尾加上“表格”。当然,第一个拥有“数据”,它是一个数据库。您的表名应该是描述性的。 {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

下面是上述查询的执行计划 enter image description here

解码以上计划: 索引查找输出id,名称
然后计算标量尝试从现有行值计算新行。在这种情况下,expr1003是我们的函数

索引搜索成本是97%,计算标量成本是3%,并且您可能知道索引搜索不是一个运算符去表获取数据。所以希望这清除您的问题