使用一组 (x,y) 值生成和填充表的最快方法

Posted

技术标签:

【中文标题】使用一组 (x,y) 值生成和填充表的最快方法【英文标题】:Fastest way to generate and populate a table with a set of (x,y) values 【发布时间】:2013-04-30 17:04:04 【问题描述】:

我正在尝试将 100,000,000 条基于坐标的简单记录插入到表中。有没有比下面的 t-sql 命令更快的方法来实现这一点

declare @x int
declare @y int
set @x = 0
set @y = 0

begin tran
while @x < 10000
begin
    while @y < 10000
    begin
        insert into world (x,y) VALUES (@x,@y)
        set @y = @y + 1
    end
    set @y = 0
    set @x = @x + 1
end
commit tran

【问题讨论】:

您在外部文件中有这些坐标吗?您可以将其批量加载到临时表中...... 我没有,但我怀疑创建文件所需的时间与上面的查询一样长。是时候进行实验了。 与 100,000,000 个单独的 INSERT 相比,使用 INSERT INTO SELECT 语法或 SELECT INTO 语法可能会更好。其中,我猜 SELECT INTO 可能会表现得更好。例如,请参阅here。 我看到您已经接受并接受了答案。但另一种选择可能是将 10000 行插入 #temp 并进行交叉连接。 我要去,你的工作很好,这是一次性的。我仍然对他的解决方案感兴趣,本周末会抽出一些时间来满足我的好奇心,运行一些基准测试。 【参考方案1】:

如果您有数字表,请使用您自己的数字表。否则,您可以使用 spt_values,如下所示。

WITH base_num AS
(SELECT number FROM master..spt_values WHERE type = 'P' AND number < 100)
, num AS 
(SELECT b1.number * 100 + b2.number AS number
 FROM base_num b1
 CROSS JOIN base_num b2
) 
INSERT INTO world (x,y)
SELECT n1.number AS x, n2.number AS y 
FROM num n1
CROSS JOIN num n2

【讨论】:

spt_values 未记录在案,可能会产生意想不到的结果。在这种情况下,它可能无法产生足够的数据来生成所需的记录。 @StingyJack,正如我在回答中提到的,如果 OP 有自己的数字表,那么应该使用它。另外,您能否举一个“spt_values 可能会产生意外结果”的示例。我真的很想知道。 它被认为是“内部”,因此没有记录。如果没有文档,那么您正在推断行为并且它可能会做一些意想不到的事情。 ***.com/a/4280038/16391 @StingyJack,如果我正确阅读了链接,答案是“为什么我们应该使用 spr_values”,而不是相反。 链接的标题不重要。关键是您正在推荐一种未记录的方法,该方法可能会产生意外或不可保证的结果,并且除非您执行其他操作,否则每个仅列出大约 2500 条记录。 2500 个元素的平方只会得到大约 6MM 的行,而 OP 需要 100MM。【参考方案2】:

如果 100 行对于服务器来说不是太大,那么这样的方法可能会起作用 - 这显然取决于您的日志文件的大小和速度。

WITH counter AS 
(SELECT TOP 10000 ROW_NUMBER() 
   OVER (ORDER BY a.[object_id], a.name, b.[object_id]) AS rownum 
   FROM sys.columns a, sys.columns b) 
INSERT INTO World (x,y) 
SELECT a.rownum, b.rownum 
  FROM counter a, counter b

【讨论】:

【参考方案3】:

如果你没有数字表,你可以用 CTE 模拟一个:

with cte as
(select 1 i union all select i+1 i from cte where i < 10000)
INSERT into World (x,y) 
SELECT x.i, y.i 
from cte x cross join cte y
option (maxrecursion 0)

【讨论】:

【参考方案4】:

你可以使用数字表

 SELECT TOP 10000 -- use a smaller value for testing, this will take a bit
        IDENTITY(INT,1,1) as N
   INTO #Numbers
   FROM Master.dbo.SysColumns sc1,
        Master.dbo.SysColumns sc2

然后像

SELECT
    n1.N as 'N1'
    , n2.N as 'N2'
INTO #values
FROM #Numbers n1
    CROSS JOIN #Numbers n2


SELECT COUNT(*) FROM #values

要获得集合的笛卡尔坐标,前提是您可以使用简化的坐标值。

【讨论】:

生成一百万个数字大约需要 12 秒。我只有一个共享的VM SQL Server可以使用,所以不敢尝试100MM。

以上是关于使用一组 (x,y) 值生成和填充表的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

在c#中填充word表的最快方法?

生成一组随机 x,y,z 数字,它们之间的差异最小,在定义的限制之间

求Lua 的元表的算术类的元方法例子(加、减、乘、除等等) ,详细的例子

确定一个值是不是在 Java 中的一组值中的最快方法是啥?

将数据插入 Oracle 表的最快方法是啥?

使用 DataContext 从 LINQ 查询中填充 DataTable 的最快方法