Может ли РЕАЛЬНЫЙ тип в SQLITE служить псевдонимом для идентификатора строки типа INTEGER, учитывая, что оба они хранятся в 8 байтах?

#c #sqlite #types #integer #rowid

Вопрос:

Из документации:

Реалы хранятся в виде 8 байт:

реальный. Значение представляет собой значение с плавающей запятой, хранящееся как 8-байтовое число с плавающей запятой IEEE.

RowID также составляет 8 байт / 64 бита

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

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

Если таблица rowid содержит первичный ключ, состоящий из одного столбца, и объявленный тип этого столбца — «ЦЕЛОЕ число» в любом сочетании верхнего и нижнего регистра, то столбец становится псевдонимом для rowid. Такой столбец обычно называют «целочисленным первичным ключом».

Что важно, если вы считаете:

Данные для таблиц rowid хранятся в виде структуры B-дерева, содержащей по одной записи для каждой строки таблицы, используя значение rowid в качестве ключа. Это означает, что извлечение или сортировка записей по идентификатору строки выполняется быстро. поиск записи с определенным идентификатором строки или для всех записей с идентификаторами строк в указанном диапазоне примерно в два раза быстрее аналогичного поиска, выполняемого путем указания любого другого ПЕРВИЧНОГО КЛЮЧА или индексированного значения.

Я создаю библиотеку хранилища ключей и значений в Qt/C с SQLITE в качестве серверной части, где любой из INTEGER, REAL, BLOB, TEXT типов данных доступен в качестве ключей. Имея INTEGER 64-разрядную версию и REAL будучи 64-разрядным, я хотел бы воспользоваться повышением производительности rowid, учитывая, что они оба 8-байтовые.

Однако SQLITE указывает только то, что INTEGER можно использовать.

Вопросы:

  1. Может ли REAL служить псевдонимом для rowid?
  2. Если нет, то почему бы и нет? Это просто недосмотр разработчиков SQLITE, или есть техническая причина, по которой это невозможно сделать?
  3. Если нет, то как бы я сделал это на Qt, где я преобразую double в a long long int с помощью его байтовой подписи, а не с помощью его значения?

Спасибо.

Ответ №1:

  1. НЕТ
  2. Если таблица идентификаторов строк содержит первичный ключ, состоящий из одного столбца, и объявленный тип этого столбца — «ЦЕЛОЕ число» в любом сочетании верхнего и нижнего регистра, то столбец становится псевдонимом для идентификатора строки

    Кроме того, в SQLite на самом деле нет типов столбцов. Идентификаторы строк всегда являются целыми числами, несмотря ни на что. Даже если бы столбец был помечен как РЕАЛЬНЫЙ, они все равно были бы целочисленными значениями. Вы можете хранить любой тип данных в любом столбце SQLite.

  3. Преобразуйте его в свой собственный программный код при чтении строк из базы данных.

Ответ №2:

rowid-это особый оптимизированный случай , если вы специально не используете БЕЗ ROWID в определении таблицы (очень редко используется), он всегда существует (с БЕЗ ROWID вы должны указать ПЕРВИЧНЫЙ КЛЮЧ).

учитывая, что оба они хранятся в 8 байтах?

ЦЕЛЫЕ числа хранятся в соответствии с:- ЦЕЛЫМ ЧИСЛОМ. Значение представляет собой целое число со знаком, хранящееся в 1, 2, 3, 4, 6, или 8 байт в зависимости от величины значения.

Может ли REAL служить псевдонимом для rowid?

Нет, так как ровид-это особый случай. Тем не менее, вы можете имитировать использование реального и привести его к целому числу, но оно должно разрешаться уникальным целым числом. (см. примеры 2, 3 и 4).

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

  1. Поскольку идентификаторы строк являются основным аспектом дизайна SQLite, как и в большинстве вещей, которые вы используете по назначению (для уникальной идентификации строки, их использование в противном случае часто приводит к тревоге).
    • Предложение БЕЗ ROWID было поздним дополнением.
  2. Обработка целых чисел выполняется быстрее, чем обработка действительных чисел.
    • Таблицы идентификаторов строк отличаются тем фактом, что все они имеют уникальный, ненулевой, подписанный 64-разрядный целочисленный идентификатор строки, который используется в качестве ключа доступа к данным в базовом механизме хранения B-дерева.
  3. Целые числа будут занимать меньше места 1-8 байт по мере необходимости, реальные всегда используют 8 байт.
  4. Это не оплошность, это особенность дизайна (см. 5.). Если вам нужен уникальный индекс в соответствии с РЕАЛЬНЫМИ значениями, вам не запрещается использовать его (возможно, без таблицы идентификаторов строк), но это приведет к снижению производительности из-за того, что вы не будете использовать самый быстрый метод идентификации строк.
  5. Документация по SQLite включает в себя

Если нет, то как бы я сделал это в Qt, где я преобразую double в длинный длинный int с помощью его байтовой подписи, а не с помощью его значения?

Вы могли бы CAST (см. Примеры 2 и 3) , НО результат ДОЛЖЕН быть уникальным ЦЕЛЫМ ЧИСЛОМ (если это ПЕРВИЧНЫЙ КЛЮЧ или УНИКАЛЬНЫЙ индекс). Конечно, вы могли бы иметь дополнительный индекс в соответствии с РЕАЛЬНЫМ значением.

Вот несколько примеров, демонстрирующих некоторые из вышеперечисленных:-

 DROP TABLE IF EXISTS example1;
DROP TABLE IF EXISTS example2;
DROP TABLE IF EXISTS example3;
DROP TABLE IF EXISTS example4;
/* rowid always exists for table unless WITHOUT ROWID table */
/* note cannot specify rowid value */
CREATE TABLE IF NOT EXISTS example1 (col1);
INSERT INTO example1 VALUES('x'),('y'),('z');
SELECT *,rowid, oid,_rowid_ FROM example1;

/* Ooops not an alias as INTEGER not specified , but rowid exists*/
CREATE TABLE IF NOT EXISTS example2 (col1, rowid_alias, PRIMARY KEY(rowid_alias));
INSERT INTO example2 VALUES('a',null),('b',CAST(10.4567 AS INTEGER)),('c',null);
SELECT *,rowid, oid,_rowid_ FROM example2;

/* rowid_alias is an alias of the rowid */
CREATE TABLE IF NOT EXISTS example3 (col1, rowid_alias INTEGER, PRIMARY KEY(rowid_alias));
INSERT INTO example3 VALUES('a',null),('b',CAST(10.4567 AS INTEGER)),('c',null);
SELECT *,rowid, oid,_rowid_ FROM example3;


/* sort of mimic rowid using real */
CREATE TABLE IF NOT EXISTS example4 (mimic_rowid);
INSERT OR IGNORE INTO example4 VALUES 
    ((coalesce((SELECT max(mimic_rowid) FROM example4),0.1234)   1.11))
;
INSERT OR IGNORE INTO example4 VALUES 
    ((coalesce((SELECT max(mimic_rowid) FROM example4),0.1234)   1.11))
;
SELECT *,rowid FROM example4;

DROP TABLE IF EXISTS example1;
DROP TABLE IF EXISTS example2;
DROP TABLE IF EXISTS example3;
DROP TABLE IF EXISTS example4;
 

Выполнение вышеуказанного:-

Первый результат показывает, что идентификатор строки существует, даже если он не имеет псевдонима:-

введите описание изображения здесь

Вторые/третьи результаты показывают, что для псевдонима идентификатора строки он должен быть ЦЕЛОЧИСЛЕННЫМ ПЕРВИЧНЫМ КЛЮЧОМ (неявно, т. Е. Указывать ПЕРВИЧНЫЙ КЛЮЧ на уровне таблицы, а не на уровне столбца). :-

  • Первый (пример 2) результат НЕ псевдоним :-

введите описание изображения здесь

  • Второй (пример 3) псевдоним :- введите описание изображения здесь
    • Примечание ПРИВЕДЕНИЕ используется для приведения РЕАЛЬНОГО к ЦЕЛОМУ ЧИСЛУ для 2-й вставки
    • как видно, 3-я вставка генерирует следующий идентификатор строки, используя максимальный существующий идентификатор строки 1 (НЕ ГАРАНТИРУЕТСЯ 1, но обычно это так).

Последний пример типа репликации (триггер сделает это автоматически) имитирует rowid, но на САМОМ ДЕЛЕ :-

введите описание изображения здесь

  • ИЛИ ИГНОРИРОВАТЬ пропустит вставку, а не завершится ошибкой, если она не уникальна

Некоторые ссылки:-