运行SQL Server Express 2008.我为某些实用程序功能创建了“数字表”。由于表填充是自动构建的一部分,因此每次部署时都会花费过多的时间。
冒着“过度优化”的风险,有人可以评论我如何能够尽快实现这一目标吗?也许使用索引填充因子或创建PK时?
IF EXISTS (SELECT * FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'Numbers') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
drop TABLE [Numbers]
end
CREATE TABLE [Numbers]
(
[Number] [int]
, CONSTRAINT [Index_Numbers] PRIMARY KEY CLUSTERED
(
[number] ASC
) ON [PRIMARY]
)
ON [PRIMARY]
Declare @cnt int
Select @cnt=0
SET NOCOUNT ON
while (@cnt<10000)
BEGIN
INSERT INTO NUMBERS(NUMBER) SELECT @cnt
SELECT @cnt=@cnt+1
end
答案 0 :(得分:12)
SQL, Auxiliary table of numbers 杰夫莫登。这是最快的
--===== Itzik's CROSS JOINED CTE method
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT N
INTO #Tally4
FROM cteTally
WHERE N <= 1000000;
GO
答案 1 :(得分:4)
必须做一些测试,在函数中包装东西并使用不同的场景来填充表格。
通过删除WHERE子句WHERE N <= @count
并添加TOP子句TOP (@count)
,可以改进Mikael提出的解决方案。对于我来说,这减少了几乎六倍的执行时间:
这是最快的算法!现在你知道了:o)
create function dbo.Numbers2(@count bigint)
RETURNS TABLE RETURN
--===== Itzik's CROSS JOINED CTE method
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT TOP (@count) N
FROM cteTally
与较慢的适应相比:
create function dbo.Numbers3(@count bigint)
RETURNS TABLE RETURN
--===== Itzik's CROSS JOINED CTE method
WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
E02(N) AS (SELECT 1 FROM E00 a, E00 b),
E04(N) AS (SELECT 1 FROM E02 a, E02 b),
E08(N) AS (SELECT 1 FROM E04 a, E04 b),
E16(N) AS (SELECT 1 FROM E08 a, E08 b),
E32(N) AS (SELECT 1 FROM E16 a, E16 b),
cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
SELECT N
FROM cteTally
WHERE N <= @count
https://stackoverflow.com/a/14386663/481812中提出的解决方案与Numbers2具有相似的性能:
create function dbo.Numbers(@count bigint)
RETURNS TABLE RETURN
with byte (n) as (
-- shortened, see the other answer for full code
CREATE TABLE #Numbers ([Number] [int])
insert #Numbers select n from dbo.Numbers(1000000)
drop table #Numbers
-- 480 - 900 ms, avg 600 ms
CREATE TABLE #Numbers ([Number] [int])
insert #Numbers select n from dbo.Numbers2(1000000)
drop table #Numbers
-- 440 - 800 ms, avg 550 ms
-- just in case you wondered how it scales, 30 times more went in in 14000,
-- Numbers and Numbers2 scale linearly
CREATE TABLE #Numbers ([Number] [int])
insert #Numbers select n from dbo.Numbers3(1000000)
drop table #Numbers
-- 2700 - 4000 ms, avg 3200 ms
CREATE TABLE #Numbers ([Number] [int] primary key)
insert #Numbers select n from dbo.Numbers(1000000)
drop table #Numbers
-- 1900 - 4000 ms, avg 3000 ms
CREATE TABLE #Numbers ([Number] [int] primary key)
insert #Numbers select n from dbo.Numbers2(1000000)
drop table #Numbers
-- 1900 - 4000 ms, avg 3000 ms
CREATE TABLE #Numbers ([Number] [int] primary key)
insert #Numbers select n from dbo.Numbers3(1000000)
drop table #Numbers
-- 4000 - 7000 ms, avg 5000 ms
CREATE TABLE PNumbers ([Number] [int] primary key)
insert PNumbers select n from dbo.Numbers(1000000)
drop table PNumbers
-- 7000 - 12000 ms, avg 10000 ms
CREATE TABLE PNumbers ([Number] [int] primary key)
insert PNumbers select n from dbo.Numbers2(1000000)
drop table PNumbers
-- 7000 - 12000 ms, avg 10000 ms
CREATE TABLE PNumbers ([Number] [int] primary key)
insert PNumbers select n from dbo.Numbers3(1000000)
drop table PNumbers
-- 7000 - 12000 ms, avg 10000 ms
CREATE TABLE #Numbers ([Number] [int] identity primary key, x bit)
INSERT INTO #Numbers(x) select 1 from dbo.Numbers2(1000000)
drop table #Numbers
-- 2000 - 4000 ms, avg 3000 ms
CREATE TABLE #Numbers ([Number] [int] identity primary key)
declare @cnt int = 0
while (@cnt<1000000)
BEGIN
INSERT INTO #Numbers DEFAULT values
set @cnt = @cnt+1
END
drop table #Numbers
-- 20000 - 22000 ms, avg 21000 ms
Numbers(n)和Numbers2(n)选项始终执行相同(最佳)。由于WHERE子句,Numbers3(n)的速度较慢。其他测试过的场景太慢而无法考虑。
插入未编制索引的临时堆最快。只要您将任何索引(已尝试)添加到列(PK群集或辅助非唯一),它就不再是数字生成,而是关于索引插入(可能还有IO)。最糟糕的是插入物理表。这必须是因为临时表不一定写入磁盘(tempdb)。
根据测量结果,你将获得
你可以完全避开物理或临时表,只使用函数,但是在随后的查询中,你将在优化器上进行搜索,因为你没有统计数字。然后你可以用查询提示来解决这个问题,这个问题不好,但有效......但是,看一下执行计划,至少可以正确估算dbo.Numbers的行数。
答案 2 :(得分:0)
您可以做的一件简单事情就是延迟创建索引,直到填充完所有数字。换句话说,将它从CREATE TABLE中删除,并在循环后添加一个CREATE INDEX语句。这将阻止在每个插入时更新索引。
答案 3 :(得分:0)
我不确定我是否同意这个体系结构,从高级别开始,但由于你只是坚持一个字段,数字从0到9999,你可以改变表定义,因此它是一个自动增量播种到从0开始。然后将默认值插入表中。那应该非常快。
您还可以使用正确的行对表进行原型设计,然后通过“复制”行来插入10,000。这意味着另一个“无”的表,可能会或可能不会解决问题。
只是两个想法。