T-SQL:生成数字组合并保存到表中
Posted
技术标签:
【中文标题】T-SQL:生成数字组合并保存到表中【英文标题】:T-SQL : generate combination of numbers and save into table 【发布时间】:2020-09-08 21:03:32 【问题描述】:我的查询可以生成 1 到 90 范围内 6 个数字的所有可能组合。
但是它在一段时间后停止工作,产生以下错误:
执行批处理时出错。错误消息是:引发了“System.OutOfMemoryException”类型的异常。
有没有办法解决这个问题以及如何将结果保存到表(不是临时表)?
WITH Numbers(N) AS
(
SELECT number
FROM master..spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 90
)
SELECT *
FROM Numbers N1
JOIN Numbers N2 ON N2.N > N1.N
JOIN Numbers N3 ON N3.N > N2.N
JOIN Numbers N4 ON N4.N > N3.N
JOIN Numbers N5 ON N5.N > N4.N
JOIN Numbers N6 ON N6.N > N5.N
【问题讨论】:
你想做什么?这将生成数以亿计的行。 我正在尝试获得一张包含 90 种组合中所有可能的 6 种的表格 【参考方案1】:评论太长了。
您的查询生成的行数实在是太多了。 1 到 90 个 evalue 之间的 6 个数字的所有可能组合为 90 ^ 6
行。
select power(cast(90 as real), 6) res
| res |
| -----------: |
| 531441000000 |
超过 5000 亿行:显然,这会耗尽数据库服务器的资源。向它扔硬件不太可能使这成为可能。你应该重新考虑你想要做什么。
【讨论】:
。 .实际上,没有重复,元组是唯一的,所以它“只有”622,614,630(90*89*88*87*8685/6!)。 @GordonLinoff:我评论了问题陈述而不是查询本身 - 实际上,它生成的行更少(不知道 OP 实际上想要什么)。我想 6 亿仍然可以说是压倒性的…… 上次我看到有人试图这样做是为了生成用于彩票目的的所有组合¯\_(ツ)_/¯【参考方案2】:您可以尝试一次填充您的表格,在每次迭代时将第一列的值增加 1。
先决条件:
-
决定列的数据类型。这些值在 1-90 之间,它们适合 tinyint(1 字节)而不是 null。 6 列 = 6 个字节
创建唯一的聚集索引,因为列的组合是唯一的。一个堆会为 RID 增加 8 字节的开销,为唯一值增加 4 字节的非唯一聚集索引(所有六列只有 6 字节)
提供数据库(可用空间+恢复模型):
(六列 x 1 字节 + 约 8 字节行开销)x 620mil = 数据库中约 9-10GB 的可用空间/存储空间,并最大限度地减少数据文件自动增长的开销。
如果可能,最好将 db 的恢复模式更改为 simple(以防止 log out of space 错误)。
如果空间使用很重要(并且有足够的 cpu 用于稍后增加的成本),您还可以考虑对“数字”表进行页面压缩。
创建数字表:
create table dbo.numstable
(
a tinyint not null,
b tinyint not null,
c tinyint not null,
d tinyint not null,
e tinyint not null,
f tinyint not null,
constraint pknumstable primary key clustered(a,b,c,d,e,f)
);
go
并填充它,一次一个列“a”值:
declare @maxa int = (select isnull(max(a), 0)+1 from dbo.numstable);
select @maxa = case when @maxa <= 85 then @maxa end;
declare @Numbers table (N tinyint primary key clustered);
insert into @Numbers(N)
select rownum --cast?
from
(
select top (90) row_number() over(order by rand()) as rownum
from master.dbo.spt_values
) as r
where rownum >= @maxa;
insert into dbo.numstable with (tablock)
(a,b,c,d,e,f)
SELECT N1.N as a, N2.N as b, N3.N as c, N4.N as d, N5.N as e, N6.N as f
FROM @Numbers N1
JOIN @Numbers N2 ON N2.N > N1.N
JOIN @Numbers N3 ON N3.N > N2.N
JOIN @Numbers N4 ON N4.N > N3.N
JOIN @Numbers N5 ON N5.N > N4.N
JOIN @Numbers N6 ON N6.N > N5.N
where N1.N = @maxa
order by N1.N, N2.N, N3.N, N4.N, N5.N, N6.N;
go 85 --iterate 85 times
如果在填充期间发生错误,请修复并再次执行填充脚本(原样)。
如果吞吐量约为 1500 万行/分钟(最坏情况),则完全填充表需要大约 40 分钟。
查询表时,您可以“利用”数据/值的性质:
--instead of ...
select count(*)
from dbo.numstable
where c = 7
and e = 44;
--...better...
select count(*)
from dbo.numstable
where a in (1, 2, 3, 4, 5)
and b in (2, 3, 4, 5, 6)
and c = 7
and e = 44;
【讨论】:
以上是关于T-SQL:生成数字组合并保存到表中的主要内容,如果未能解决你的问题,请参考以下文章