Упорядоченная вставка в следующий неиспользуемый индекс, общий SQL - PullRequest
1 голос
/ 25 января 2011

Были разные подобные вопросы, но они либо ссылались на слишком конкретную БД, либо предполагали несортированные данные.

В моем случае SQL должен быть переносимым, если это возможно.Указанный столбец индекса представляет собой кластеризованный PK, содержащий метку времени.

Метка времени на 99% больше времени, чем ранее вставленное значение.Однако в редких случаях он может быть меньше или конфликтовать с существующим значением.

В настоящее время я использую этот код для вставки новых значений:

IF NOT EXISTS (select * from Foo where Timestamp = @ts) BEGIN
    INSERT INTO Foo ([Timestamp]) VALUES (@ts);
END
ELSE BEGIN
    INSERT INTO Foo ([Timestamp]) VALUES (
    (SELECT Max (t1.Timestamp) - 1
    FROM Foo t1
    WHERE Timestamp < @ts
    AND NOT EXISTS (select * from Foo t2 where t2.Timestamp = t1.Timestamp - 1))
    );
END;

Если строка еще не используетсяПросто вставьте.Иначе, найдите ближайшую свободную строку с меньшим значением, используя проверку EXISTS.

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

Редактировать Спасибо заВаши комментарии и ответы до сих пор.

Чтобы объяснить природу моего случая: отметка времени является единственным значением, когда-либо использованным для сортировки данных, незначительными несоответствиями можно пренебречь.Отношений ФК нет.

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

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

Ответы [ 4 ]

4 голосов
/ 25 января 2011

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

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

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

Временная метка BTW является зарезервированным словом SQL-сервера и никогда не должна использоваться в качестве имени поля.

3 голосов
/ 25 января 2011

Если вы не можете гарантировать, что ваши значения PK уникальны, то это не хороший кандидат в PK.Особенно, если это временная метка - я уверен, что Goldman Sachs понравится, если их высокочастотные торговые программы могут вызывать коллизии на вставке и вставляться на 1 микросекунду раньше, потому что система изменяет временную метку своей торговли.

Поскольку вы не можете гарантировать уникальность временных меток, лучше выбрать колонку int / bigint с автоматическим приращением plain-jane, которая решает проблему коллизий, дает вам хороший метод получения порядка вставки, и вывсе еще можно сортировать по полю отметки времени, чтобы получить хороший прямой график, если это необходимо.

3 голосов
/ 25 января 2011

Одной из идей будет добавление суррогатного идентификатора / идентификатора / ключа последовательности, чтобы первичный ключ стал (отметка времени, новый ключ).

Таким образом вы сохраняете порядок строк и уникальность без кода

Чтобы выполнить приведенный выше код, вам нужно поиграться с детализацией блокировки и подсказками параллелизма в приведенном выше коде, или TRY / CATCH, чтобы повторить попытку с альтернативным значением (SQL Server). Это удаляет переносимость.Однако при большой нагрузке вам придется продолжать повторную попытку, поскольку альтернативное значение может уже существовать.

0 голосов
/ 25 января 2011

Метка времени как ключ?В самом деле?Каждый раз, когда строка обновляется, ее метка времени изменяется.Тип данных отметки времени SQL Server предназначен для использования в строках версий.Это не то же самое, что временная метка SQL ANSI / ISO - это эквивалент типа данных даты и времени SQL Server.

Что касается «сортировки» по столбцу меток времени: единственное, что гарантировано с меткой времениявляется то, что каждый раз, когда строка вставляется или обновляется, она получает новое значение метки времени, и это значение является уникальным 8-октетным двоичным значением, отличным от предыдущего значения, назначенного строке, если оно есть.Нет гарантии, что это значение имеет какую-либо связь с системными часами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...