2016-04-26 2 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 

Это решает проблему производительности, но добавляет накладные расходы, чтобы написать же выбрать два времени. Любые другие предложения были бы замечательными.

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

Реальная проблема производительности здесь заключается в существовании скалярной функции. Они, как известно, бедные исполнители. Затем, когда вы вставляете его в столбец, он становится еще хуже. Возможно, мы можем помочь вам создать встроенную функцию оценки таблиц. Он будет более гибким и лучше справится с этим. Нам просто нужны детали о том, что он делает, и о структурах таблиц, которые он использует. http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –

+1

А? Как «обход» отличается от исходного запроса? –

+0

@GordonLinoff В более раннем запросе столбец данных неоднократно выбирается, однако в более позднем запросе он выбирается по проецируемым данным, следовательно, быстрее. – fredzyadi

ответ

4

You» решая проблему, которая не существует. Вы, кажется, думают, что

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

Я не могу присоединиться к нему, так как таблица уже соединена с другой таблицей. Не могли бы вы ответить на вопрос? Есть ли способ сохранить значение столбца в переменной и использовать его в запросе select? Или вы думаете, что это невозможно. – fredzyadi

+0

Нет, невозможно «сохранить» значение столбца в «переменной» и повторно использовать его в вызове функции так, как вы этого хотите. Могут быть другие способы повышения производительности, но вы не предоставляете достаточно информации, чтобы дать содержательное предложение. –

+0

«Я не могу присоединиться к нему, поскольку таблица уже соединена с другой таблицей». Не уверен, что вы имеете в виду здесь - вы можете присоединиться к нескольким таблицам. –

3

Как говорит D Stanley, вы пытаетесь решить некоторые проблемы, которая не существует. Я бы добавил, что вы вообще не должны использовать эту функцию. 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 страшные имена таблиц. Конечно, это таблицы, поэтому нет необходимости ставить «таблицу» в конце имени. Кроме того, конечно, первый хранит «данные», это база данных. Названия ваших таблиц должны быть описательными. Что точно делает 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

Декодирование выше плана: индекса искать выходы идентификатора, имя
Затем вычислить скаляр пытается рассчитать новые строки из существующей строки values.in этого случая expr1003, который наша функция

индекс искать стоимость 97%, вычислить скаляр стоимость 3% и, как вы могли бы знать индекс искать не является оператором, который идет к столу, чтобы получить data.so надеюсь, что это очищает ваш вопрос

Смежные вопросы