2016-04-26 96 views
3

我有以下选择使用标量函数来获取全名的查询。我想通过使用变量消除冗余,但迄今为止没有成功。我的查询是如何在选择查询中使用变量?

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 

这解决了性能问题,但增加的开销写入相同选择两个时间。任何其他建议都会很棒。

数据表看起来像这样

+----+----------+------------+ 
| 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

实这里的性能问题是标量函数的存在。他们是臭名昭着的表演者。那么当你将它粘在一列中时就会变得更糟。也许我们可以帮助您创建一个内联表值函数。它将更加灵活,并且一举成功。我们只需要一些关于它的功能和它使用的表结构的细节。 http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –

+1

咦? “解决方法”与原始查询有什么不同? –

+0

@GordonLinoff在前面的查询中,数据列被重复选择,但是在后面的查询中,它是对投影数据的选择因此更快。 – fredzyadi

回答

4

你”功能重新解决不存在的问题。你似乎认为

select 
a.Id, 
a.UserName, 
getFullName(a.UserName), 
a.CreateTime 
from DataTable; 

背后都有一些相对昂贵的过程中得到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 
+0

我无法加入它,因为该表已与另一个表连接。你能回答所问的问题吗?有没有一种方法可以将列值存储在变量中并在选择查询中使用它?或者你认为这是不可能的。 – fredzyadi

+0

不,不可能将列值“存储”到“变量”中,并按照您希望的方式在函数调用中重复使用它。可能有其他方法来提高性能,但是您没有提供足够的信息来提供有意义的建议。 –

+0

“我无法加入它,因为表格已经与另一个表格相连接。”不确定你的意思 - 你可以加入多个表格。 –

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是表可怕的名字。当然,他们是桌子,所以不需要在名称末尾加上“桌子”。此外,当然第一个拥有“数据”,这是一个数据库。你的表名应该是描述性的。 究竟确实DataTable持有?

如果你打算在将来进行SQL开发,那么我强烈建议你阅读一些关于这个主题的介绍性书籍,并观看尽可能多的教程视频。

+0

这些名称仅用于举例。我不愿意在这里发表我的实际查询与真正的表名和真正的表数据。我认为这个例子可以达到目的,如果你仍然无法回答所问的问题,那么确定你可以继续前进并观察尽可能多的教程;) – fredzyadi

+1

这个建议并不仅仅基于命名约定。从你的问题中可以明显看出,你不了解关系数据库背后的一些基本概念。这不是为了个人的侮辱,如果看起来这样,我很抱歉。由于开发人员认为他们可以只安装SQL并开始编码,所以我用我的很多钱作为修复代码的顾问。我永远不会失去工作,所以我更希望更多的开发人员完全避免这些问题。 –

+0

它是如何“显而易见”。好,我会道歉,而且我真的不在乎你做了多少,因为我现在只关心我的问题。但是,我感谢您对我的关注以及您为这个社区做出的贡献。谢谢。 – fredzyadi

2

标量UDF将执行的每一行,但不是defintely你think.below的方式是样品演示,这证明了相同的执行计划..

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,名称
然后计算标试图从现有的行计算新行values.in这种情况下expr1003这是我们的功能

指数寻求成本是97%,计算成本的标量为3%,正如你可能知道索引查找是不是运营商都到表得到data.so希望这会清除你的问题