Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
Доброго дня, коллеги!

Возможно что-то где-то не дочитал, вопрос к тем кто дочитал. Почему вот этот запрос:

SELECT x.n, a.id
  FROM (SELECT NEWID() n) x
  JOIN (SELECT 1 id UNION ALL SELECT 2) a
    ON 1=1


Возвращает разные гуиды хотя по логике запрос в секции FROM должен выполняться 1 раз и должен вернуть 1 значение. Это происки оптимизатора? Никак нельзя получить одинаковый гуид без использования переменной?
15 янв 18, 15:44    [21108164]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Maxx
Member [скрыт]

Откуда:
Сообщений: 24290
а план посмотреть слабо ? там все написанно.. ведь
15 янв 18, 15:51    [21108205]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6794
Drunik,

SELECT TOP (SELECT 1) NEWID()

но это вроде баг
15 янв 18, 15:56    [21108233]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
Maxx
а план посмотреть слабо ? там все написанно.. ведь


написанно обычно в подъезде... вот план

|--Compute Scalar(DEFINE:([Expr1000]=newid()))
|--Constant Scan(VALUES1)),((2))))

Мне от этого плана легче не стало. Я понимаю что обращение происходит к функции 2 раза - я не понимаю почему? И можно ли что то сделать чтобы это обращение делалось 1 раз?
15 янв 18, 15:57    [21108239]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
TaPaK
Drunik,

SELECT TOP (SELECT 1) NEWID()

но это вроде баг


Спасибо, но это тоже не помогает.
15 янв 18, 15:59    [21108245]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6794
Drunik
TaPaK
Drunik,

SELECT TOP (SELECT 1) NEWID()

но это вроде баг


Спасибо, но это тоже не помогает.


SELECT 
	(SELECT TOP (SELECT 1) NEWID())
FROM 
(SELECT 1 id UNION ALL SELECT 2 ) a
15 янв 18, 16:01    [21108255]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6794
или через джоин если хочется

SELECT 
	*
FROM 
(SELECT 1 id UNION ALL SELECT 2 ) a
LEFT JOIN
(SELECT TOP (SELECT 1) NEWID() x) b
ON 1 = 1
15 янв 18, 16:08    [21108293]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
TaPaK,

Большое спасибо, так работает, но в голове не очень помещается.
Что такое TOP (SELECT 1) - это какая-то недекларированная фича? План запроса отличается кардинально. Очень бы хотелось узнать о такой конструкции подробнее.
15 янв 18, 16:09    [21108301]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
Я имею в виду различия плана вот с таким запросом:

SELECT a.id,
	(SELECT TOP (1) NEWID())
FROM 
(SELECT 1 id UNION ALL SELECT 2 ) a


А вот такой запрос всё равно не работает:

SELECT x.n, a.id
  FROM (SELECT TOP (SELECT 1) NEWID() n) x
  JOIN (SELECT 1 id UNION ALL SELECT 2) a
    ON 1=1


Есть ощущение что это какие-то игры оптимизатора и на какой-нибудь версии sql-сервера это всё перестанет работать (а возможно и сейчас не везде работает, проверял только на 2008 и 2014). Хотелось бы какую то теоретическую базу понять.
15 янв 18, 16:14    [21108320]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6794
Drunik,

я же написал "но это вроде баг"
сейячас работает вплоть до 2016. Используйте переменную
15 янв 18, 16:16    [21108330]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
TaPaK,

Я понял, спасибо, будем знать.
15 янв 18, 16:19    [21108352]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
invm
Member

Откуда: Москва
Сообщений: 9127
Drunik,

SELECT a.n, a.id
  FROM (SELECT NEWID() n) x cross apply
  (SELECT x.n, 1 id UNION ALL SELECT x.n, 2) a

Drunik
Есть ощущение что это какие-то игры оптимизатора
Ага, игры.
Сравните планы вашего запроса и моего. И обратите внимание где и сколько раз вычисляется newid().
15 янв 18, 16:26    [21108380]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
ATI.HeNRy
Member

Откуда:
Сообщений: 23
First_value(newid()) over(order by (select null))
Если лень.
15 янв 18, 17:30    [21108647]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
invm
Drunik,

SELECT a.n, a.id
  FROM (SELECT NEWID() n) x cross apply
  (SELECT x.n, 1 id UNION ALL SELECT x.n, 2) a

Drunik
Есть ощущение что это какие-то игры оптимизатора
Ага, игры.
Сравните планы вашего запроса и моего. И обратите внимание где и сколько раз вычисляется newid().


Сломался ваш запрос на чуть более реальном примере:

SELECT a.n, a.id
  FROM (SELECT NEWID() n) x 
 CROSS apply (SELECT x.n, id=number FROM master.dbo.spt_values WHERE type='P' AND number BETWEEN 1 AND 10) a


Вобщем Бог с ним с этим гуидом, не ломайте голову коллеги, я свои проблемы решил добавлением переменой - просто и надёжно.
15 янв 18, 19:07    [21108856]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
invm
Member

Откуда: Москва
Сообщений: 9127
Drunik
Сломался ваш запрос на чуть более реальном примере
Переменная конечно надежнее. А если понадобится, например, запихнуть сей запрос в инлайновую функцию?

Суть решения - обязательная зависимость в cross apply результата внутреннего запроса от внешнего.
А в вашем чуть более реальном примере это не так.

Более правильный вариант:
SELECT x.n, a.id
  FROM (SELECT NEWID() n) x cross apply
  (SELECT 1 id UNION ALL SELECT 2 where x.n >= 0x0) a
  
SELECT a.n, a.id
  FROM (SELECT NEWID() n) x 
 CROSS apply (SELECT x.n, id=number FROM master.dbo.spt_values WHERE type='P' AND number BETWEEN 1 AND 10 and x.n >= 0x0) a
15 янв 18, 19:35    [21108903]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
invm
Суть решения - обязательная зависимость в cross apply результата внутреннего запроса от внешнего.
А в вашем чуть более реальном примере это не так.


Уважаемый invm, это всё отлично и про инлайновые функции и вьюхи вы абсолютно правы - в жизни всё требуется, но вы это где-то всё прочитали, в какой-то документации или это всё на уровне шаманства и танцев с бубнами? Интерес действительно не праздный, т.к. кроме гуидов часто встречаются запросы с обращением к какой-нибудь инлайн функции, которая вполне могла бы вызваться 1 раз, но вызывается как назло по кол-ву строк в запросе, например что то вроде такого:

declare @d datetime = getdate()
select * from Table1 where field1>dbo.func1(@d)


В такого рода запросах (более сложных) оптимизатор вдруг может делать множество обращений к func1. Если вы могли бы дать какие-то общие рекомендации, правила как этого избежать, то это, думаю, было бы полезно для многих. Конечно очень желательно всё это подкрепить какими то ссылками на документацию или статьи. Не хотелось бы при необходимости перехода на новую версию sql-сервера рвать на всех местах волосы по причине необходимости переписывания половины объектов в БД из-за того, что такая конструкция перестанет работать. В любом случае спасибо за информацию.
15 янв 18, 22:55    [21109132]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Гигабайт Мегабайтович Килобайтов
Member [заблокирован]

Откуда:
Сообщений: 5975
Drunik,

знать как работает sql-сервер, а именно читать справку, ходить на курсы ))
16 янв 18, 10:54    [21109812]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
Гигабайт Мегабайтович Килобайтов
Drunik,

знать как работает sql-сервер, а именно читать справку, ходить на курсы ))


Уважаемый Гигабайт Мегабайтович, а зачем тогда нужен форум? Всё же можно прочитать в справке и походить на курсы? Я думал он нужен для обмена знаниями, видимо ошибался? Кто решает какие можно задавать вопросы на форуме, а какие нельзя? Вы?
16 янв 18, 11:05    [21109845]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6794
Drunik,

простой ответ: не используйте скалярки в WHERE и тчк :)
16 янв 18, 11:11    [21109860]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Гигабайт Мегабайтович Килобайтов
Member [заблокирован]

Откуда:
Сообщений: 5975
Drunik
Гигабайт Мегабайтович Килобайтов
Drunik,

знать как работает sql-сервер, а именно читать справку, ходить на курсы ))


Уважаемый Гигабайт Мегабайтович, а зачем тогда нужен форум? Всё же можно прочитать в справке и походить на курсы? Я думал он нужен для обмена знаниями, видимо ошибался? Кто решает какие можно задавать вопросы на форуме, а какие нельзя? Вы?

ну если вы хотите на форуме про льва толстого что-бы вам процитировать всю "войну и мир " то что вы ожидаете в ответ услышать?
а что можно и что нельзя - есть в правилах форума. И также в рекомендациях.
16 янв 18, 11:12    [21109864]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
TaPaK
Member

Откуда: Kiev
Сообщений: 6794
Гигабайт Мегабайтович Килобайтов,

плохо что нет рекомендации "не пуустозвонить"
16 янв 18, 11:15    [21109868]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Drunik
Member

Откуда: Москва
Сообщений: 99
TaPaK
Гигабайт Мегабайтович Килобайтов,

плохо что нет рекомендации "не пуустозвонить"


Поддерживаю полностью.
TaPaK, спасибо за рекомендации!
16 янв 18, 11:21    [21109885]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7403
Drunik,

если функция indeterministic, то сервер вынужден выполнить вызов ее для каждой строки. Т.е. функция при том же аргументе вернет другое значение. В том числе это системные функции даты-времени (rowguid также функция даты-времени).

Если правильно помню, то в некоторых случаях скалярную функцию можно привязать к схеме и они станет deterministic и запрос вычислит ее один раз.

Может это мои фантазии, надо проверять :)
16 янв 18, 11:48    [21109994]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 3464
Гигабайт Мегабайтович Килобайтов
Drunik
пропущено...


Уважаемый Гигабайт Мегабайтович, а зачем тогда нужен форум? Всё же можно прочитать в справке и походить на курсы? Я думал он нужен для обмена знаниями, видимо ошибался? Кто решает какие можно задавать вопросы на форуме, а какие нельзя? Вы?

ну если вы хотите на форуме про льва толстого что-бы вам процитировать всю "войну и мир " то что вы ожидаете в ответ услышать?
а что можно и что нельзя - есть в правилах форума. И также в рекомендациях.


при всех недостатках ТС в данной теме - разве он просил "процитировать войну и мир" или всю документацию?
16 янв 18, 12:09    [21110053]     Ответить | Цитировать Сообщить модератору
 Re: Как получить одинаковый GUID  [new]
invm
Member

Откуда: Москва
Сообщений: 9127
Drunik
Интерес действительно не праздный, т.к. кроме гуидов часто встречаются запросы с обращением к какой-нибудь инлайн функции, которая вполне могла бы вызваться 1 раз, но вызывается как назло по кол-ву строк в запросе
Вы путаете инлайновую со скалярной.
Drunik
В такого рода запросах (более сложных) оптимизатор вдруг может делать множество обращений к func1
Это зависит от детерминированности функции, формы запроса и оптимизатора.
+ Пример
use tempdb;
go

create function dbo.fn1
(
 @x int
)
returns varchar(200)
as
begin
 return (select name from sys.objects where object_id = @x);
end;
go

create function dbo.fn2
(
 @x int
)
returns varchar(200)
as
begin
 return 'x = ' + cast(@x as varchar(10));
end;
go

create function dbo.fn3
(
 @x int
)
returns varchar(200)
with schemabinding
as
begin
 return 'x = ' + cast(@x as varchar(10));
end;
go

select objectproperty(object_id, 'IsDeterministic'), name from sys.objects where name in (N'fn1', N'fn2', N'fn3') and schema_name(schema_id)  = N'dbo';
go

select top (5) * into #t from master.dbo.spt_values;
go

set statistics xml on;

/*5 раз*/select * from #t where name = dbo.fn1(1);
/*5 раз*/select * from #t where name = dbo.fn2(1);
/*1 раз*/select * from #t where name = dbo.fn3(1);
/*1 раз*/select * from #t where name = (select dbo.fn1(1));
/*1 раз*/select * from #t where name = (select dbo.fn2(1));

declare @x int = 1;

/*5 раз*/select * from #t where name = dbo.fn1(@x);
/*5 раз*/select * from #t where name = dbo.fn2(@x);
/*1 раз*/select * from #t where name = dbo.fn3(@x);
/*5 раз*/select * from #t where name = (select dbo.fn1(@x));
/*5 раз*/select * from #t where name = (select dbo.fn2(@x));
/*1 раз*/select * from #t where name = (select dbo.fn1(@x)) option (recompile);
/*1 раз*/select * from #t where name = (select dbo.fn2(@x)) option (recompile);

set statistics xml off;
go

drop table #t;
drop function dbo.fn1, dbo.fn2, dbo.fn3;
go
16 янв 18, 12:12    [21110067]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Microsoft SQL Server Ответить