Гарантирует ли ограничение PRIMARY KEY, определенное на уровне таблицы, AUTOINCREMENT и никакие значения не используются повторно? - PullRequest
0 голосов
/ 28 марта 2019

Рассмотрим следующее определение таблицы:

CREATE TABLE names (
    id INTEGER,
    name TEXT NOT NULL,
    PRIMARY KEY (id)
)

Гарантирует ли это, что id будет автоматически увеличиваться для каждой новой вставки И что значения для удаленных строк не будут использоваться повторно?

Я посмотрел в документации по Sqlite3, но не смог найти ответ.

1 Ответ

0 голосов
/ 28 марта 2019

id INTEGER PRIMARY KEY по своему усмотрению гарантирует (требует) уникальное целочисленное значение и будет, если никакое значение не назначено специально, предоставлять его до тех пор, пока наибольшее значение не достигнет максимально допустимого значения для 64-разрядного целого числа со знаком (9223372036854775807), после чего неиспользованноезначение может быть найдено и применено.

При AUTOINCREMENT существует гарантия (если не обойти) всегда предоставлять более высокое значение, НО, если достигается 9223372036854775807 вместо выделения неиспользуемого числа, в результате возникнет ошибка SQLITE_FULL.Это единственное различие с точки зрения того, какое число будет присвоено.

Ни один из них не гарантирует монотонно возрастающее значение.

Без AUTOINCREMENT расчет / алгоритм эквивалентен

  • 1 + max (rowid), и если значение больше 9223372036854775807, делается попытка найти неиспользуемое и, следовательно, более низкое значение.

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

При AUTOINCREMENT расчет / алгоритм равен

  • больше 1 + max (rowid) или SELECT seq FROM sqlite_sequence WHERE name = 'the_table_name_the_rowid_is_being_assigned_to', а если значение больше 9223372036854775807, то SQLITE_FULL ERROR.

  • , если это не таквероятность того, что максимальное значение rowid предназначено для строки, которая в итоге не вставляется, и, следовательно, может стать пробелом.

Ответ, возможно, лучше всего сформулировать так: лучше / рекомендуется использовать столбец id исключительно для его предполагаемой цели, для эффективной идентификации строки, а не каксредство обработки других требований к данным, и в этом случае нет необходимости в AUTOINCREMENT (который имеет накладные расходы )

Короче

Гарантирует ли эточто идентификатор будет автоматически увеличиваться

NO

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

NO для данного кода

для: -

CREATE TABLE names (id INTEGER PRIMARY KEY AUTOINCREMENT name TEXT NOT NULL)

снова NO , как будто достигается 9223372036854775807, тогда возникнет ошибка SQLITE_FULL,в противном случае ДА .


Таким образом, действительно, AUTOINCREMENT действительно действительно (только если идентификатор используется как ожидалось / предполагалось), когда 9223372036854775807-ая строка была вставлена.

Возможно, рассмотрим следующее: -

DROP TABLE IF EXISTS table1;
DROP TABLE IF EXISTS table2;

CREATE TABLE IF NOT EXISTS table1 (id INTEGER PRIMARY KEY, somecolumn TEXT);
CREATE TABLE IF NOT EXISTS table2 (id INTEGER PRIMARY KEY AUTOINCREMENT, somecolumn TEXT);

INSERT INTO table1 VALUES (9223372036854775807,'blah'); 
INSERT INTO table2 VALUES (9223372036854775807,'blah');
INSERT INTO table1 (somecolumn) VALUES(1),(2),(3); 
SELECT * FROM table1;
INSERT INTO table2 (somecolumn) VALUES(1),(2),(3);

Это создает две одинаковые таблицы, единственное отличие заключается в использовании AUTOINCREMENT.В каждую вставлена ​​строка с максимально допустимым значением для столбца id .

Затем делается попытка вставить 3 строки, в которых SQLite будет назначать id ..

3 строки вставляются в таблицу без AUTOINCREMENT, но при использовании AUTOINCREMENT строки не вставляются.согласно: -

CREATE TABLE IF NOT EXISTS table1 (id INTEGER PRIMARY KEY, somecolumn TEXT)
> OK
> Time: 0.098s


CREATE TABLE IF NOT EXISTS table2 (id INTEGER PRIMARY KEY AUTOINCREMENT, somecolumn TEXT)
> OK
> Time: 0.098s


INSERT INTO table1 VALUES (9223372036854775807,'blah')
> Affected rows: 1
> Time: 0.094s


INSERT INTO table2 VALUES (9223372036854775807,'blah')
> Affected rows: 1
> Time: 0.09s


INSERT INTO table1 (somecolumn) VALUES(1),(2),(3)
> Affected rows: 3
> Time: 0.087s


SELECT * FROM table1
> OK
> Time: 0s


INSERT INTO table2 (somecolumn) VALUES(1),(2),(3)
> database or disk is full
> Time: 0s

Результат SELECT для таблицы1 (который может отличаться из-за случайности) был: -

enter image description here

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