SqlServer Случайная генерация данных наблюдения - PullRequest
0 голосов
/ 19 декабря 2010

У меня вопрос, почему выходные данные этих двух запросов различаются.Я ожидал бы, что они будут работать одинаково.

Запрос 1:

declare @cache table(originalValue nvarchar(255), obfuscateValue nvarchar(255));

declare @table1 table(c char(1));
declare @i1 int;
set @i1 = ASCII('0');

while @i1 <= ASCII('9')
begin
    insert into @table1 (c)
    select (CHAR(@i1))    

    set @i1 = @i1 +1;
end


insert into @cache (originalValue, obfuscateValue)
select [firstname], 
        (select top 1 c from @table1 order by NEWID()) + 
        (select top 1 c from @table1 order by NEWID()) 
from Customer
where [firstname] is not null

select * from @cache;

Запрос 2:

declare @cache table(originalValue nvarchar(255), obfuscateValue nvarchar(255));

declare @table1 table(c char(1));
declare @i1 int;
set @i1 = ASCII('0');

while @i1 <= ASCII('9')
begin
    insert into @table1 (c)
    select (CHAR(@i1))    

    set @i1 = @i1 +1;
end


insert into @cache (originalValue)
select [firstname]
from Customer
where [firstname] is not null

update c
set c.obfuscateValue = t.Value
from @cache c
join 
(
    select originalValue,
    (       
        (select top 1 c from @table1 order by NEWID()) + 
        (select top 1 c from @table1 order by NEWID()) 
    ) as Value
    from @cache
) t on t.originalValue = c.originalValue

select * from @cache;

Они должны делать то же самое, но первый запрос возвращает следующие результаты:

Jonathon    73
Everett 73
Janet   73
Andy    73
Shauna  73

И второй:

Jonathon    82
Everett 40
Janet   68
Andy    79
Shauna  29

Как вы заметили, второй столбец во втором результате имеет разные значения,а first - те же значения.

Похоже, что в первом запросе

(select top 1 c from @table1 order by NEWID()) + 
        (select top 1 c from @table1 order by NEWID())

вызывается только один раз.

Может кто-нибудь объяснить эту тайну?

Ответы [ 3 ]

0 голосов
/ 20 декабря 2010

Одна строка?

SELECT
     RIGHT( --number of zeros to match expected max length. Or use REPLICATE.
        '000000' + CAST(
          --The 2 newid() expression means we'll get a larger number
          --less chance of using leading static zeroes
          CAST(CHECKSUM(NEWD_ID()) as bigint) * CAST(CHECKSUM(NEWD_ID()) as bigint)
            as varchar(30))
        --The 3 gives us the desired mask. Currently 3 digits.
        , 3)
0 голосов
/ 20 декабря 2010

Вы правы в своем предположении, что первый запрос запускает «выбрать верх» только один раз. Поведение происходит из-за того, как оптимизатор решил оптимизировать запрос. Он решил, потому что подзапросы (самые популярные запросы) являются автономными и не связаны с внешним запросом выбора, поэтому он использует оператор Tablespool (Lazy Spool) в плане выполнения. Это приводит к тому, что значение select top будет помещено в базу данных tempdb для повторного использования.

Поскольку оптимизатор решает использовать оператор Nested Loops для объединения всех данных, перепривязка не требуется, вместо повторного применения запросов для каждой входной внешней строки используется буферное значение.

Во время второго запроса оптимизатор решил не использовать оператор Tablespool (я считаю, что на самом деле входная таблица была из базы данных tempdb). Таким образом, у вас есть подзапросы select top, которые применяются повторно для каждой строки ввода из временной таблицы.

При необходимости вы можете использовать подсказки таблицы / запроса, если хотите заставить план выполнения работать так, как вам нужно.

0 голосов
/ 19 декабря 2010

Я думаю, что случайные значения могут быть сгенерированы другим способом.

Это как сгенерировать [a-zA-Z] {3,6}

declare @min int, @max int;
declare @alpha varchar(max)

set @min = 3;
set @max = 6;
set @alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

declare @cache table(originalValue nvarchar(255), obfuscateValue nvarchar(255));

insert into @cache (originalValue, obfuscateValue)
select [firstname], LEFT(t.Value, case when t.maxLen < @min then @min else t.maxLen end)
from Customer 
join
(
    select ABS(CHECKSUM(NEWID()))%@max + 1 as maxLen,
            SUBSTRING(@alpha, ABS(CHECKSUM(NEWID()))%LEN(@alpha) + 1, 1) +
            SUBSTRING(@alpha, ABS(CHECKSUM(NEWID()))%LEN(@alpha) + 1, 1) +
            SUBSTRING(@alpha, ABS(CHECKSUM(NEWID()))%LEN(@alpha) + 1, 1) +
            SUBSTRING(@alpha, ABS(CHECKSUM(NEWID()))%LEN(@alpha) + 1, 1) +
            SUBSTRING(@alpha, ABS(CHECKSUM(NEWID()))%LEN(@alpha) + 1, 1) +
            SUBSTRING(@alpha, ABS(CHECKSUM(NEWID()))%LEN(@alpha) + 1, 1) as Value
)t on t.Value is not null
where [firstname] is not null

select * from @cache;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...