【问题标题】:Faster way to insert records into database将记录插入数据库的更快方法
【发布时间】:2018-02-09 18:13:28
【问题描述】:

所以我目前有一个包含大约 70,000 个名称的数据库表。我想要做的是从该数据库中获取 3000 条随机记录并将它们插入到另一个表中,其中每个名称都有一行用于所有其他名称。换句话说,新表应该是这样的:

John, jerry
john, alex
john, sam
jerry, alex
jerry, sam
alex, sam

这意味着我应该在表格中添加 n 行的总和。我目前的策略是使用两个嵌套的 for 循环一次添加这些行,然后从要添加的名称列表中删除第一个名称,以确保我没有具有不同顺序的重复记录。

我的问题是:有没有更快的方法来做到这一点,也许是通过并行 for 循环或 PLINQ 或我没有提到的其他选项?

【问题讨论】:

标签: c# sql sql-server parallel.foreach


【解决方案1】:

给定一个带有 nvarchar(50) 列“名称”的表“名称”,其中包含以下数据:

Adam
Bob
Charlie
Den
Eric
Fred

这个查询:

-- Work out the fraction we need
DECLARE @frac AS float;
SELECT @frac = CAST(35000 AS float) / 70000;

-- Get roughly that sample size
WITH ts AS (
SELECT Name FROM Names
WHERE @frac >= CAST(CHECKSUM(NEWID(), Name) & 0x7FFFFFFF AS float) / CAST (0X7FFFFFFF AS int)
)

-- Match each entry in the sample with all the other entries
SELECT x.Name + ', ' + y.Name
FROM ts AS X
CROSS JOIN
Names AS Y
WHERE x.Name <> y.Name

产生表单的结果

Adam, Bob
Adam, Charlie
Adam, Den
Adam, Eric
Adam, Fred
Charlie, Adam
Charlie, Bob
Charlie, Den
Charlie, Eric
Charlie, Fred
Den, Adam
Den, Bob
Den, Charlie
Den, Eric
Den, Fred

结果会因运行而异; 70000 个样本中的 3000 个样本将具有 大约 3000 * 70000 个结果行。我使用了 35000./70000,因为我使用的样本量只有 6。

如果您只需要使用示例中的名称,请将 CROSS JOIN Names AS Y 更改为 CROSS JOIN ts AS Y,然后将有大约 3000 * 3000 个结果行。

参考:随机抽样方法取自Limiting Result Sets by Using TABLESAMPLE中的“重要”部分。

【讨论】:

  • 你有重复。查看 OP 的示例输出。
  • @Paparazzi 我宁愿希望 OP 的示例输出不是他们想要的,他们对输出的描述是。让我们拭目以待:)
  • @Paparazzi 啊,我明白你的意思了。我已要求 OP 澄清问题的另一部分。
  • 酷,我又发了一条斜线
【解决方案2】:

你需要找出随机部分

select t1.name, t2.name 
from table t1 
join table t2 
on t1.name < t2.name 
order by t1.name, t2.name

你需要实现newid

declare @t table (name varchar(10) primary key);
insert into @t (name) values 
       ('Adam')
     , ('Bob')
     , ('Charlie')
     , ('Den')
     , ('Eric')
     , ('Fred');
declare @top table (name varchar(10) primary key);
insert into @top (name)
select top (4) name from @t order by NEWID();

select * from @top;

select a.name, b.name
from @top a  
join @top b 
  on a.name < b.name  
order by a.name, b.name;

【讨论】:

  • order by t1.name &lt; t2.name?
【解决方案3】:

使用数字表模拟名称。

单个查询,使用三角连接

WITH all_names 
     AS (SELECT n, 
                'NAME_' + Cast(n AS VARCHAR(20)) NAME 
         FROM   number 
         WHERE  n < 70000), 
     rand_names 
     AS (SELECT TOP 3000 * 
         FROM   all_names 
         ORDER  BY Newid()), 
     ordered_names 
     AS (SELECT Row_number() 
                  OVER ( 
                    ORDER BY NAME) rw_num, 
                NAME 
         FROM   rand_names) 
SELECT n1.NAME, 
       n2.NAME 
FROM   ordered_names n1 
       INNER JOIN ordered_names n2 
               ON n2.rw_num > n1.rw_num   

【讨论】:

  • 你测试过这个吗? CTE 只是语法,可以多次调用。我做了测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-31
  • 1970-01-01
相关资源
最近更新 更多