Descrição:
Eu tento inserir 1 milhão de linhas em uma tabela vazia no MSSQL 2012 Express. Aqui meu roteiro:
-- set statistics time off
drop table t1
create table t1 (id int, a text, b text)
go
-- #1 - 1,000,000 - 30s -> 45s
with ID(number) as
(
select 1 as number
union all
select number + 1
from ID
where number < 1000000 + 1
)
insert into t1
select number, 'a_' + cast (number as varchar), 'b_' + cast (number/2 as varchar)
from ID
option(maxrecursion 0)
-- #2 - 1 million rows => ~140,000 rows = 120s (have to cancel query)
declare @count int
set @count = 0
while @count < 1000000
begin
set @count = @count + 1
insert into t1
values(@count, 'a_' + cast (@count as varchar), 'b_' + cast (@count/2 as varchar))
end
-- #3 - ~1,300,000 rows - 18s -> 20s
with temp as
(
SELECT ROW_NUMBER() OVER(ORDER BY a.object_id) as tcount
from sys.all_columns a, sys.all_columns b
where a.object_id = b.object_id
)
insert into t1
select tcount, 'a_' + cast (tcount as varchar), 'b_' + cast (tcount/2 as varchar)
from temp
go
declare @count int
set @count = 0
while @count < 3
begin
with temp as (select max(id) + 1 as max_id from t1)
insert into t1
select max_id, 'a_' + cast (max_id as varchar), 'b_' + cast (max_id/2 as varchar)
from t1, temp
set @count = @count + 1
end
-- #4 -- 1,000,000 = 3s -> 4s (have to drop t1 first)
with a(k) as
(
select 1 as k
union all
select k + 1 from a where k < 99 + 1
) ,
t2 as (
select row_number() over(order by x.k) as k
from a x , a y , a z
)
select k as id , 'a_' + cast (k as varchar) as a, 'b_' + cast (k/2 as varchar) as b into t1
from t2
Pergunta:
Depois de pesquisar, encontrei 4 soluções. Existe alguma solução melhor (não usar dados de cópia de arquivos)?
Itzik Ben-Gan usa a seguinte abordagem Esta é provavelmente a maneira mais rápida que ele encontrou e ele é bastante inteligente :-)
Uma variação da resposta de dnoeth :
Isso evita armazenar os valores de a e b; seus valores serão calculados em tempo de execução conforme necessário. Isso pode ser um pouco trapaceiro, mas tem vantagens:
ROW_NUMBER
retorna bigint (8 bytes descompactado).Alternativamente, armazenando todas as colunas na tabela:
Observe a conversão para integer na coluna id e o uso de um comprimento específico nos tipos varchar . Ver:
Maus hábitos para chutar: declarando VARCHAR sem (comprimento) por Aaron Bertrand
Método 1: @dnoeth acima, tempo de inserção: 1077ms - 1180ms (teste de 10 vezes)
Método 2: Eu tento inserir usando este método, tempo de inserção 989ms -> 1132ms
É simples.
Método 3 : da ideia de Paul White, 450ms
Outra variação da resposta de dnoeth:
Muito mais eficiente usar 6 como base já que 6^8 (1 679 616) é muito mais próximo de 1000000 do que 2^32 (4 294 967 296)