2009-08-26 9 views
0

У меня есть таблица, которая потенциально будет иметь большое количество вставок в секунду, и я пытаюсь выбрать тип первичного ключа, который я хочу использовать. Для примера, это таблица пользователей. Я пытаюсь выбрать между использованием GUID и BIGINT в качестве первичного ключа и, в конечном счете, как UserID в приложении. Если я использую GUID, я сохраняю поездку в базу данных для генерации нового идентификатора, но GUID не является «удобным для пользователя», и невозможно разбить таблицу на этот идентификатор (который я планирую сделать). Использование BIGINT гораздо удобнее, но генерировать проблему - я не могу использовать IDENTITY (есть причина для этого), поэтому мой единственный выбор - иметь некоторую вспомогательную таблицу, которая будет содержать последний использованный ID, а затем я вызываю это хранится в процессе:Выбор типа первичного ключа

create proc GetNewID @ID BIGINT OUTPUT 
as 
begin 
update HelperIDTable set @ID=id, id = id + 1 
end 

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

Мне очень нравится идея использования BIGINT как pk, но проблема с узким местом касается меня - есть ли способ приблизиться к оценке количества идентификаторов, которые он может производить в секунду? Я понимаю, что это сильно зависит от аппаратного обеспечения, но есть ли какие-либо физические ограничения и в какой степени мы смотрим? 100 'S/сек? 1000-х/сек?

Любые идеи о том, как подойти к проблеме, высоко оценены! Эта проблема не позволяет мне спать уже много ночи!

Спасибо! Andrey

+2

Не могли бы вы быть более конкретными относительно того, почему вы не можете использовать IDENTITY? –

+2

Кроме того, BIGINT - очень большой int, для вас не хватит INT? Если это таблица пользователей, насколько вероятно, что у вас будет больше, чем 2 147 483 647 пользователей? –

+0

, если вы вызываете эту процедуру в транзакции с другими транзакциями CRUD, вы будете блокировать и вызывать ожидание –

ответ

2

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

То, что я настоятельно рекомендую не делать, это использовать столбец GUID в качестве ключа кластеризации, который по умолчанию делает SQL Server, если вы специально не говорите ему об этом.

Как Kimberly Tripp - Королева Индексации - и другие заявили много раз - GUID, поскольку ключ кластеризации не является оптимальным, поскольку из-за его случайности это приведет к массивной фрагментации страницы и индекса и, как правило, к плохая производительность.

Да, я знаю - в SQL Server 2005 есть newsequentialid(), но даже это не является поистине и полностью последовательным и, следовательно, также страдает от тех же проблем, что и GUID, - это немного менее заметно.

Тогда есть еще одна проблема: кластерный ключ в таблице будет добавлен к каждой записи и для каждого некластеризованного индекса в вашей таблице, так что вы действительно хотите убедиться, что он не меньше возможное. Как правило, INT с 2+ миллиардами строк должен быть достаточным для подавляющего большинства таблиц - и по сравнению с GUID в качестве ключа кластеризации вы можете сэкономить сотни мегабайт памяти на диске и в памяти сервера.

Итак, чтобы подвести итог: если у вас есть действительно веская причина, я бы всегда рекомендовал поле INT IDENTITY в качестве основного/кластерного ключа на вашем столе.

Марк

+0

Что вы имеете в виду, когда говорите, что newsequentialid() не является действительно и полностью последовательным? –

+0

+1 для сообщения Ким Триппа по GUID. Хорошо знать о физической реализации ... – Anon246

+0

@kyralessa: это последовательное какое-то время - тогда есть прыжки в последовательности, а затем она может быть последовательной на некоторое время снова. Я ожидал, что если я вложу 10'000 строк, у них будет поистине последовательный новый GUID, которого не было бы. –

0

попытайтесь поразить свой дБ скриптом, возможно, используя jmeter для имитации одновременных ударов. Возможно, вы можете просто измерить, сколько нагрузки вы можете обработать. Также ваша БД может вызвать горло бутылки. Который из них? Я бы предпочел PostgreSQL для большой нагрузки, например yahoo и skype также

1

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

Если вам нужен «читаемый человеком» идентификатор, вы можете использовать автоматический приращение int при сохранении. Для разбиения на разделы вы также можете создать BIGINT позже по расписанию базы данных для многих пользователей одним выстрелом.

+2

Фактически, если вы используете GUID и кластерную таблицу, ваша производительность будет ужасной, поскольку записи будут вставлены в случайные пятна CL IX и вызовут много разбиений на страницы. Я не рекомендую это делать. – Anon246

+1

как твоя производительность? GUID как первичный (и, следовательно, ключ кластеризации по умолчанию) ужасны для производительности. Ознакомьтесь с отличным сообщением Ким Триппа на тему: http://sqlskills.com/BLOGS/KIMBERLY/category/Indexes.aspx –

+0

Да, но вы можете создать кластер PK nmon и установить кластерный индекс в столбце BIGINT. – Mischa

1

вы хотите первичный ключ, по коммерческим причинам, или clustred ключ, для проблем хранения ли? См. stackoverflow.com/questions/1151625/int-vs-unique-identifier-for-id-field-in-database для более подробного сообщения на тему ПК по кластерному ключу.

Вам действительно нужно выяснить, почему вы не можете использовать IDENTITY. Генерирование идентификаторов вручную и специально на сервере с дополнительным rountrip и обновлением, чтобы генерировать каждый идентификатор для вставки, он не будет масштабироваться. Вам повезло, что вы достигнете более низких 100 секунд в секунду. Проблема заключается не только в времени роутинга и времени обновления, но, прежде всего, от взаимодействия обновления генерации идентификаторов со вставкой-вставкой: транзакция пакетного ввода будет генерировать сериализацию генерации. Взаимодействие состоит в том, чтобы отделить генерацию идентификатора от отдельного сеанса, чтобы он мог автокомментировать, но тогда пакетная вставка бессмысленна, потому что идентификатор не переносится: имеет, чтобы дождаться флеш-записи после каждого идентификатора, определенного для фиксации. По сравнению с этим uuid будет запускаться круги вокруг вашей генерации идентификатора вручную. Но uuid - это ужасный выбор для кластеризованного ключа из-за фрагментации.

0

Идея, требующая серьезного тестирования: попробуйте создать (вставить) новые строки в партиях - скажем 1000 (10 000? 1 М?) Времени. Вы могли бы иметь таблицу мастера (он же узкое место) листинг следующий использовать, или вы могли бы иметь запрос, который делает что-то вроде

select min(id) where (name = '') 

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

Опция разбиения на таблицы. Предполагая столбец идентификатора bigint, как вы определяете раздел? Если вы разрешаете 1G строк в день, вы можете настроить новый раздел вечером (день1 = 1,000,000,000 через 1999,999,999, day2 = 2,000,000,000 через 29999999999 и т. Д.), А затем поменять его, когда он будет готов. Вы, конечно, ограничены 1000 разделами, поэтому с помощью bigints у вас закончится раздел, прежде чем вы закончите идентификаторы.

+0

В основном мысли здесь, возможно, не так много помогают. –

Смежные вопросы