我试图插入随机从预先定义的值列表值转换成用于测试的表。 我尝试使用这个StackOverflow的问题找到了解决办法:
stackoverflow.com/.../update-sql-table-with-random-value-from-other-table
当我试过了这一点,我所有的“随机”的价值观正在插入的是完全对所有3000条记录是相同的。
当我运行,实际上选择随机行查询的一部分,但它选择一个随机记录每次我用手运行它的时候,所以我知道的查询工作。 我最好的猜测所发生的事情是:
- SQL Server在优化
SELECT
不知何故,不允许子查询进行评估不止一次 - 随机值的种子在每个记录相同的查询更新
我卡在什么我的选择是。 我做得不对,或者是有另一种方式我应该这样做呢?
这是我使用的代码:
DECLARE @randomStuff TABLE ([id] INT, [val] VARCHAR(100))
INSERT INTO @randomStuff ([id], [val])
VALUES ( 1, 'Test Value 1' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 2, 'Test Value 2' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 3, 'Test Value 3' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 4, 'Test Value 4' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 5, 'Test Value 5' )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 6, null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 7, null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 8, null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 9, null )
INSERT INTO @randomStuff ([id], [val])
VALUES ( 10, null )
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID())
当查询引擎看到这个...
(SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID())
......这一切都喜欢,“OOOOH,一个超高速缓存标量子查询,我要缓存!”
你需要欺骗查询引擎误以为它是不可缓存的。 jfar的答案很接近,但查询引擎很聪明,看到的tautalogy MyTable.MyColumn = MyTable.MyColumn
,但它不是足够聪明,通过这个看到。
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 val
FROM @randomStuff r
INNER JOIN MyTable _MT
ON M.Id = _MT.Id
ORDER BY NEWID())
FROM MyTable M
通过引入外部表(MT)到子查询中,查询引擎假设子查询将需要重新评估。 任何真正的工作,但我MyTable.Id的(假设的)主键去,因为它会被编入索引,并会增加非常小的开销。
游标可能会是一样快,但肯定是没有的乐趣。
我已经受够了这个戏,并发现了一个相当哈克的方式与使用中间表变量来做到这一点。
一旦@randomStuff设置,我们这样做(注意我的情况,@MyTable是表变量,相应地调整你的正常的表):
DECLARE @randomMappings TABLE (id INT, val VARCHAR(100), sorter UNIQUEIDENTIFIER)
INSERT INTO @randomMappings
SELECT M.id, val, NEWID() AS sort
FROM @MyTable AS M
CROSS JOIN @randomstuff
所以在这一点,我们有与(mytable的ID,随机值)的每一种组合的中间表,以及用于特定于该组合的每一行的随机排序值。 然后
DELETE others FROM @randomMappings AS others
INNER JOIN @randomMappings AS lower
ON (lower.id = others.id) AND (lower.sorter < others.sorter)
这是一个老把戏其删除除了具有较低排序值对于一个给定MyTable.id所有行 - 加入表本身,其中值较小,并删除任何地方这样的联接成功。 这只是留下的最低值。 因此,对于每个MyTable.id,我们只需要留下一个(随机)值。然后,我们只需将其回表:
UPDATE @MyTable
SET MyColumn = random.val
FROM @MyTable m, @randomMappings AS random
WHERE (random.id = m.id)
就大功告成了!
我说,这是哈克...
我现在没有时间来检查这个权利,但我的直觉告诉我,如果你要在服务器上创建一个函数来获取随机值,它不会优化它。
那么你将有
UPDATE MyTable
Set MyColumn = dbo.RANDOM_VALUE()
有没有优化怎么回事。
您的使用选择单个值的子查询,有什么优化。
您也可以尝试把一列从表的更新中选择,看看有没有改变任何东西。 这可能触发评估为MyTable的每一行
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID()
WHERE MyTable.MyColumn = MyTable.MyColumn )
我想出了一个解决方案,它是一个黑客位和效率非常低(10〜秒更新3000条记录)。 因为这是被用来生成测试数据,我就不必关心速度但是。
在这个解决方案,我遍历表中的每一行,同时更新值一行。 看来工作:
DECLARE @rows INT
DECLARE @currentRow INT
SELECT @rows = COUNT(*) FROM dbo.MyTable
SET @currentRow = 1
WHILE @currentRow < @rows
BEGIN
UPDATE MyTable
SET MyColumn = (SELECT TOP 1 [val] FROM @randomStuff ORDER BY NEWID())
WHERE MyPrimaryKey = (SELECT b.MyPrimaryKey
FROM(SELECT a.MyPrimaryKey, ROW_NUMBER() OVER (ORDER BY MyPrimaryKey) AS rownumber
FROM MyTable a) AS b
WHERE @currentRow = b.rownumber
)
SET @currentRow = @currentRow + 1
END