Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Вставка в 1 таблицу vs в несколько таблиц  [new]
Acce_Ekb
Member

Откуда: Екатеринбург
Сообщений: 87
Добрый день,

занимаюсь нормализацией (большой таблицы в несколько маленьких), и возникло интересное наблюдение.

Пусть есть 1 широкая таблица с M достаточно длинных столбцов. Создадим M узких таблиц с одним столбцом, чтоб разнести по одному столбцу из той широкой таблицы.
Буем вставлять, например, 10 тыс. строк в одну широкую и в M узких таблиц (так, чтобы суммарный объем данных был примерно одинаков).
Получаем: вставка в широкую таблицу почти в M раз быстрее, чем в M узких таблиц.

Тестовый скрипт:
set nocount on
go

-- Вставка в 1 общую таблицу
if object_id( 'dbo.TestWrite' ) is not null
  drop table dbo.TestWrite
create table dbo.TestWrite
  ( s1 varchar(500)
  , s2 varchar(500)
  , s3 varchar(500)
  )

declare @i int
set @i = 0

select getdate()

while @i < 10000
begin
  insert into dbo.TestWrite ( s1, s2, s3 )
    select replicate( 'a', 500 )
         , replicate( 'b', 500 )
         , replicate( 'c', 500 )

  set @i = @i + 1
end


select getdate()
exec sp_spaceused TestWrite
go

if object_id( 'dbo.TestWrite' ) is not null
  drop table dbo.TestWrite
go


-- Вставка в узкие таблицы
if object_id( 'dbo.TestWrite1' ) is not null
  drop table dbo.TestWrite1
if object_id( 'dbo.TestWrite2' ) is not null
  drop table dbo.TestWrite2
if object_id( 'dbo.TestWrite3' ) is not null
  drop table dbo.TestWrite3

create table dbo.TestWrite1 ( s varchar(500) )
create table dbo.TestWrite2 ( s varchar(500) )
create table dbo.TestWrite3 ( s varchar(500) )

declare @i int

select getdate()

set @i = 0
while @i < 10000
begin
  insert into dbo.TestWrite1 ( s ) select replicate( 'a', 500 )
  insert into dbo.TestWrite2 ( s ) select replicate( 'b', 500 )
  insert into dbo.TestWrite3 ( s ) select replicate( 'c', 500 )
  set @i = @i + 1
end

select getdate()

exec sp_spaceused TestWrite1
exec sp_spaceused TestWrite2
exec sp_spaceused TestWrite3
go

if object_id( 'dbo.TestWrite1' ) is not null
  drop table dbo.TestWrite1
if object_id( 'dbo.TestWrite2' ) is not null
  drop table dbo.TestWrite2
if object_id( 'dbo.TestWrite3' ) is not null
  drop table dbo.TestWrite3
go

Результат:
2009-05-28 10:33:37.540
2009-05-28 10:33:39.260
( ~ 1.7 сек )

name        rows        reserved           data               index_size
----------- ----------- ------------------ ------------------ ----------
TestWrite   10000       16072 KB           16056 KB           8 KB      


2009-05-28 10:33:39.273
2009-05-28 10:33:44.337
( ~ 5.1 сек )

name        rows        reserved           data               index_size
----------- ----------- ------------------ ------------------ ----------
TestWrite1  10000       6280 KB            6216 KB            8 KB      

name        rows        reserved           data               index_size
----------- ----------- ------------------ ------------------ ----------
TestWrite2  10000       6280 KB            6216 KB            8 KB      

name        rows        reserved           data               index_size
----------- ----------- ------------------ ------------------ ----------
TestWrite3  10000       6280 KB            6216 KB            8 KB      


Вопрос: почему так отличается время вставки при почти одинаковом объеме вставляемых данных ?
28 май 09, 08:38    [7237699]     Ответить | Цитировать Сообщить модератору
 Re: Вставка в 1 таблицу vs в несколько таблиц  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74927
Ну, во-первых, заворачивание вставки в транзакцию, практически нивелирует разницу:


------------------------------------------------------ 
2009-05-28 09:07:17.033
------------------------------------------------------ 
2009-05-28 09:07:18.653

                                                       
------------------------------------------------------ 
2009-05-28 09:07:18.723
------------------------------------------------------ 
2009-05-28 09:07:20.360

А во-вторых, не стоит забывать, что во втором случае серверу надо производить больше операций IO со страницами, что подтверждается результатами sp_spaceused.
28 май 09, 09:10    [7237741]     Ответить | Цитировать Сообщить модератору
 Re: Вставка в 1 таблицу vs в несколько таблиц  [new]
Acce_Ekb
Member

Откуда: Екатеринбург
Сообщений: 87
pkarklin,

1. Про оборачивание в транзакции знаю. Специально тестовый пример сделан без этого.
2.
автор
во втором случае серверу надо производить больше операций IO со страницами, что подтверждается результатами sp_spaceused

Имхо, не убедительно подтверждается :) в первом случае надо выделить и записать 16072 KB, во втором случае 3 раза по 6280 KB (т.е. в сумме около 18800 КБ).

Может, мне надо смотреть в сторону количества операций с логом транзакций, их-то действительно в 3 раза больше во втором примере..
28 май 09, 09:23    [7237760]     Ответить | Цитировать Сообщить модератору
 Re: Вставка в 1 таблицу vs в несколько таблиц  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74927
автор
Про оборачивание в транзакции знаю. Специально тестовый пример сделан без этого.
...
Может, мне надо смотреть в сторону количества операций с логом транзакций, их-то действительно в 3 раза больше во втором примере..


Скорее всего да.
28 май 09, 09:28    [7237774]     Ответить | Цитировать Сообщить модератору
 Re: Вставка в 1 таблицу vs в несколько таблиц  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74927
автор
Имхо, не убедительно подтверждается :) в первом случае надо выделить и записать 16072 KB, во втором случае 3 раза по 6280 KB (т.е. в сумме около 18800 КБ).


Что в результате дает 15% разницы в кол-ве страниц.
28 май 09, 09:28    [7237776]     Ответить | Цитировать Сообщить модератору
 Re: Вставка в 1 таблицу vs в несколько таблиц  [new]
Acce_Ekb
Member

Откуда: Екатеринбург
Сообщений: 87
pkarklin,

точно, если этот кусок
  insert into dbo.TestWrite1 ( s ) select replicate( 'a', 500 )
  insert into dbo.TestWrite2 ( s ) select replicate( 'b', 500 )
  insert into dbo.TestWrite3 ( s ) select replicate( 'c', 500 )

завернуть в транзакцию, то время почти равное.

( я сначала подумала, что вы предлагаете весь скрипт завернуть в одну транзакцию, там разница во времени почти не видна, потому что вообще время выполнения очень маленькое).

Спасибо за идею:)
28 май 09, 09:30    [7237777]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить