Создание первичного ключа для временной таблицы - когда? - PullRequest
20 голосов
/ 23 июня 2009

У меня есть хранимая процедура, которая работает с большим количеством данных. У меня есть эти данные, вставляемые во временную таблицу. Общий поток событий что-то вроде

CREATE #TempTable (
    Col1    NUMERIC(18,0) NOT NULL,    --This will not be an identity column.
    ,Col2   INT NOT NULL,
    ,Col3   BIGINT,

    ,Col4   VARCHAR(25) NOT NULL,
    --Etc...

    --
    --Create primary key here?
)


INSERT INTO #TempTable
SELECT ...
FROM MyTable
WHERE ...

INSERT INTO #TempTable
SELECT ...
FROM MyTable2
WHERE ...

--
-- ...or create primary key here?

Мой вопрос: когда наилучшее время для создания первичного ключа в моей таблице #TempTable? Я предположил, что я должен создать ограничение / индекс первичного ключа после того, как вставлю все данные, потому что для индекса нужны быть реорганизованным при создании информации первичного ключа. Но я понял, что моё подчеркивающее предположение может быть неверным ...

Если это уместно, используемые мной типы данных реальны. В таблице #TempTable мой основной ключ будет составлять Col1 и Col4.

Обновление: В моем случае я дублирую первичный ключ исходных таблиц. Я знаю, что поля, которые будут составлять мой первичный ключ, всегда будут уникальными. Я не беспокоюсь о неудачной таблице изменения, если я добавлю первичный ключ в конце.

Хотя, кроме этого, мой вопрос все еще остается в силе, предполагая, что оба удастся ?

P.S. Извините, если это дубликат. Это достаточно просто, чтобы это могло быть, но я не смог найти ничего подобного.

Ответы [ 9 ]

15 голосов
/ 23 июня 2009

Это зависит много.

Если вы сделаете индекс первичного ключа кластеризованным после загрузки, вся таблица будет перезаписана, поскольку кластерный индекс на самом деле не является индексом, это логический порядок данных. Ваш план выполнения на вставках будет зависеть от индексов на месте, когда план определен, и если кластеризованный индекс на месте, он будет сортироваться до вставки. Обычно вы увидите это в плане выполнения.

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

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

Однако, как отметили другие, создание индекса может завершиться неудачей. Кроме того, временная таблица не существует изолированно. Предположительно, есть лучший индекс для чтения данных из него для следующего шага. Этот индекс должен быть либо создан, либо создан. Это , где вы должны найти компромисс между скоростью и надежностью (сначала примените PK и любые другие ограничения) и скоростью позже (по крайней мере, используйте кластерный индекс, если он у вас будет) .

6 голосов
/ 23 июня 2009

Если для модели восстановления вашей базы данных задано простое или массовое ведение журнала, SELECT ... INTO ... UNION ALL может быть самым быстрым решением. SELECT .. INTO - это массовая операция, а массовые операции минимально регистрируются.

например:

-- first, create the table
SELECT ...
INTO #TempTable
FROM MyTable
WHERE ...
UNION ALL
SELECT ...
FROM MyTable2
WHERE ...

-- now, add a non-clustered primary key:
-- this will *not* recreate the table in the background
-- it will only create a separate index
-- the table will remain stored as a heap
ALTER TABLE #TempTable ADD PRIMARY KEY NONCLUSTERED (NonNullableKeyField)

-- alternatively:
-- this *will* recreate the table in the background
-- and reorder the rows according to the primary key
-- CLUSTERED key word is optional, primary keys are clustered by default
ALTER TABLE #TempTable ADD PRIMARY KEY CLUSTERED (NonNullableKeyField) 

В противном случае, Кейд Ру получил хороший совет: до или после.

3 голосов
/ 23 июня 2009

Вы также можете создать первичный ключ перед вставками - если первичный ключ находится в столбце идентификаторов, то вставки будут выполняться последовательно в любом случае, и не будет никакой разницы.

2 голосов
/ 23 июня 2009

Даже более важно, чем соображения производительности, если вы не АБСОЛЮТНО, на 100% уверены, что в таблицу будут вставлены уникальные значения, сначала создайте первичный ключ. В противном случае первичный ключ не будет создан.

Это предотвращает вставку дубликатов / неверных данных.

1 голос
/ 12 августа 2012

Мне было интересно, смогу ли я улучшить очень-очень "дорогую" хранимую процедуру, требующую кучу проверок при каждой вставке в таблицы, и наткнулся на этот ответ. В Sproc несколько временных таблиц открываются и ссылаются друг на друга. Я добавил первичный ключ в оператор CREATE TABLE (хотя мои операторы выбора используют оператор WHERE NOT EXISTS для вставки данных и обеспечения уникальности), и время выполнения было сокращено НА ЧАСТО. Я настоятельно рекомендую использовать первичные ключи. Всегда, по крайней мере, попробуйте это, даже если вы думаете, что вам это не нужно.

1 голос
/ 23 июня 2009

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

Если вы добавляете первичный ключ после всех вставок, каждая строка должна сопоставляться с каждой другой строкой. Поэтому я предполагаю, что раннее добавление первичного ключа обходится дешевле.

Но, возможно, у Sql Server есть действительно умный способ проверки уникальности. Поэтому, если вы хотите быть уверенным, измерьте это!

0 голосов
/ 14 мая 2018

Когда вы добавляете PK при создании таблицы - проверка вставки имеет значение O(Tn) (где Tn - это "n-тое треугольное число", то есть 1 + 2 + 3 ... + n), потому что, когда вы вставляете x-ю строку, оно проверяется по ранее вставленные строки "x - 1"

Когда вы добавляете PK после вставки всех значений - проверяющее устройство равно O(n^2), потому что при вставке x-й строки оно проверяется по всем n существующим строкам.

Первый, очевидно, быстрее, поскольку O(Tn) меньше O(n^2)

P.S. Пример: если вы вставите 5 строк, это будет 1 + 2 + 3 + 4 + 5 = 15 операций против 5^2 = 25 операций

0 голосов
/ 23 июня 2009

Я не планировал на это отвечать, так как не уверен на 100% в своих знаниях об этом. Но так как не похоже, что вы получаете много откликов ...

Насколько я понимаю, PK - это уникальный индекс, и когда вы вставляете каждую запись, ваш индекс обновляется и оптимизируется. Итак ... если вы сначала добавите данные, а затем создадите индекс, индекс будет оптимизирован только один раз.

Итак, если вы уверены, что ваши данные чистые (без дублированных данных ПК), я бы сказал, вставьте, а затем добавьте ПК.

Но если ваши данные могут содержать дублирующиеся данные ПК, я бы сказал, сначала создайте ПК, поэтому он сработает как можно скорее.

0 голосов
/ 23 июня 2009

Я не думаю, что это имеет какое-либо существенное значение в вашем случае:

  • либо вы платите штраф понемногу, с каждой отдельной вставкой
  • или вы заплатите больший штраф после всех вставок, но только один раз

Когда вы создаете его заранее, до начала вставки, вы могли бы потенциально обнаружить нарушения PK при вставке данных, если значение PK не создано системой.

Но кроме этого - нет большой разницы, на самом деле.

Марк

...