Максимальное значение столбца идентификации в БД SQLite

У меня чисто академический вопрос о базах данных SQLite.

Я использую SQLite.net для использования базы данных в моем проекте WinForm, и когда я настраивал новую таблицу, я задумался о максимальных значениях столбца идентификатора.

Я использую IDENTITY для своего [ID] столбца, который согласно сопоставлениям типов данных SQLite.net , эквивалентно DbType.Int64. Обычно я начинаю свои столбцы идентификаторов с нуля (с этой строкой в ​​качестве тестовой записи) и автоматически увеличиваю базу данных.

Максимальное значение (Int64.MaxValue) - 9,223,372,036,854,775,807. Для моих целей я никогда даже не скрою поверхность при достижении этого максимума, но что происходит в базе данных, которая это делает? Пытаясь прочитать это, я обнаружил, что DB2, по-видимому, «оборачивает» значение вокруг отрицательного значения (-9,223,372,036,854,775,807) и увеличивает оттуда, пока база данных не сможет вставить строки, потому что столбец идентификатора должен быть уникальным.

Это то, что происходит в SQLite и / или других механизмах баз данных?


person Jared Harley    schedule 13.06.2009    source источник
comment
Официальная документация SQLite охватывает это на sqlite.org/autoinc.html, я добавил более подробный ответ ниже.   -  person Martin C.    schedule 17.09.2010


Ответы (4)


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

person Alex Martelli    schedule 13.06.2009
comment
Мне всегда нравится такая проверка здравомыслия, когда я зацикливаюсь на проблемах, хотя обычно я о них не думаю. : - / - person tgray; 10.08.2009
comment
Вряд ли малая доля. Согласно Википедии, en.wikipedia.org/wiki/Homo_sapiens Homo Sapiens существует уже, наверное, два трети этого промежутка времени. - person Jim Dennis; 22.04.2010

IDENTITY на самом деле не является правильным способом автоматического увеличения в SQLite. Это потребует от вас увеличения уровня приложения. В оболочке SQLite попробуйте:

create table bar (id IDENTITY, name VARCHAR);
insert into bar (name) values ("John");
select * from bar;

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

С другой стороны, если вы это сделаете:

create table baz (id INTEGER PRIMARY KEY, name VARCHAR);
insert into baz (name) values ("John");
select * from baz;

это будет 1, как я думаю, вы ожидаете.

Обратите внимание, что существует также АВТОИНКОМАТИКАЦИЯ ПЕРВИЧНОГО КЛЮЧА. Основное отличие состоит в том, что AUTOINCREMENT гарантирует, что ключи никогда не будут использоваться повторно. Поэтому, если вы удалите Джона, 1 никогда не будет повторно использоваться в качестве идентификатора. В любом случае, если вы используете PRIMARY KEY (с необязательным AUTOINCREMENT) и исчерпываете идентификаторы, SQLite должен завершиться ошибкой с SQLITE_FULL, а не циклически.

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

insert into bar VALUES ("What the hell", "Bill");
insert into bar VALUES (-9, "Mary");

Оба они полностью верны. Они были бы действительны и для баз. Однако с помощью baz вы можете избежать ручного указания id. Таким образом, в столбце id никогда не будет мусора.

person Matthew Flaschen    schedule 13.06.2009
comment
Интересная информация, мне нужно взглянуть на это. Прямо сейчас я создаю свои базы данных с помощью конструктора баз данных Visual Studios 2008. Что всегда вызывает у меня цикл, так это то, что сам sqlite не имеет типов, поэтому я обычно использую страницу, на которую я ссылаюсь, для определения типов данных, устанавливаю первый столбец как Name: ID, Type: integer, я не разрешаю нули, а затем установите для столбца первичный ключ. На самом деле я не очень хорошо знаком с оболочкой SQLite. Тем не менее, спасибо за информацию! - person Jared Harley; 13.06.2009

В документации по адресу http://www.sqlite.org/autoinc.html указано, что ROWID попытается найти неиспользуемое значение с помощью рандомизации, как только оно достигнет своего максимального числа.

Для AUTOINCREMENT он будет терпеть неудачу с SQLITE_FULL при всех попытках вставить в эту таблицу, если в таблице было максимальное значение:

Если таблица ранее содержала строку с максимально возможным ROWID, то новые INSERT не разрешены, и любая попытка вставить новую строку завершится ошибкой SQLITE_FULL.

Это необходимо, поскольку AUTOINCREMENT гарантирует, что идентификатор монотонно увеличивается.

person Martin C.    schedule 17.09.2010

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

Что же касается того, что на самом деле произойдет, то это совершенно неясно, как база данных справится с этим. Проблема возникает в момент фактического СОЗДАНИЯ идентификатора, который слишком велик для поля, поскольку маловероятно, что движок внутренне использует тип данных более 64 бит. В этот момент можно только догадываться ... внутренний язык, используемый для разработки движка, может вырваться, число может незаметно обернуться вокруг и просто вызвать нарушение первичного ключа (при условии, что существует конфликтующий идентификатор), мир может прийти к конец из-за вашего переполнения и т. д.

Но прагматично Алекс прав. Теоретический предел количества строк, задействованных здесь (при условии, что это один идентификатор на строку, а не какие-либо махинации, связанные с вставкой идентификатора читера), в основном сделает ситуацию спорной, поскольку к тому времени, когда вы, возможно, сможете ввести такое количество строк в даже колоссальная скорость вставки мы все равно умрем, так что это не имеет значения :)

person Adam Robinson    schedule 13.06.2009