2016-04-26 97 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希望這會清除你的問題