![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
По умолчанию у каждой строки в SQLite
есть специальная колонка, обычно названная
"rowid",
которая однозначно определяет строку в таблице.
Однако, если фраза "WITHOUT ROWID" добавляется до конца
CREATE TABLE,
то специальная колонка "rowid" опущена. Иногда есть преимущества
для исключения rowid. Таблица WITHOUT ROWID это таблица, которая использует
кластерный индекс в качестве первичного ключа. Чтобы создать таблицу WITHOUT ROWID, просто добавьте ключевые слова
"WITHOUT ROWID" в CREATE TABLE: Как со всем синтаксисом SQL, не имеет значения регистр ключевых слов.
Можно написать "WITHOUT rowid", "without rowid" или вообще "WiThOuT rOwId",
это будет означать то же самое. Каждая таблица WITHOUT ROWID должна иметь
PRIMARY KEY.
Ошибка поднята, если CREATE TABLE с WITHOUT ROWID не имеет PRIMARY KEY. В большинстве контекстов специальную колонку "rowid"
нормальных таблиц можно также назвать "oid" или "_rowid_".
Однако, только "rowid" работает ключевым словом в CREATE TABLE. SQLite version 3.8.2
(2013-12-06) или позже необходим, чтобы использовать WITHOUT ROWID.
Попытка открыть базу данных, которая содержит одну или несколько таблиц
WITHOUT ROWID, используя более раннюю версию SQLite, приведет к ошибке
"malformed database schema". WITHOUT ROWID есть только в SQLite и несовместим ни с каким другим
дивжком SQL, насколько мы знаем. В изящной системе все таблицы
вели бы себя как WITHOUT ROWID даже без ключевых слов WITHOUT ROWID.
Однако, когда SQLite был сначала разработан, он использовал только целое
число rowid
для ключей строки , чтобы упростить внедрение. Этот подход работал хорошо
много лет. Но поскольку требования к SQLite выросли, потребность в таблицах,
в которых PRIMARY KEY действительно соответствовал основному ключу строки,
стала более острой. Понятие WITHOUT ROWID было добавлено, чтобы удовлетворить
те потребности, не ломая назад совместимость с миллиардами баз данных
SQLite (приблизительно 2013). WITHOUT ROWID является оптимизацией. Это не обеспечивает новых
возможностей. Что-либо, что может быть сделано, используя WITHOUT ROWID,
может также быть сделано точно таким же образом, и точно тем же самым
синтаксисом, используя обычный rowid. Единственное преимущество WITHOUT ROWID
это то, что оно может иногда использовать меньше дискового пространства и/или
работать немного быстрее, чем обычный rowid. По большей части обычные rowid и WITHOUT ROWID
взаимозаменяемые. Но есть некоторые дополнительные ограничения на
WITHOUT ROWID, которые не относятся к обычным rowid: У каждой таблицы WITHOUT ROWID
должен быть PRIMARY KEY. Попытка создать WITHOUT ROWID без PRIMARY
KEY приводит к ошибке. Специальные поведения связаны с тем, что
"INTEGER PRIMARY KEY"
не применяется на таблицах WITHOUT ROWID. В обычной таблице "INTEGER
PRIMARY KEY" означает, что эта колонка просто псевдоним для rowid.
Но нет никакого rowid в WITHOUT ROWID, поэтому
особое значение больше не применяется. Столбец "INTEGER PRIMARY KEY" в
таблице WITHOUT ROWID работает как "INT PRIMARY KEY" в обычной таблице:
это PRIMARY KEY, у которого есть
близость integer. AUTOINCREMENT не работает на
WITHOUT ROWID. Механизм AUTOINCREMENT
принимает присутствие rowid и таким образом, это не работает с WITHOUT ROWID.
Ошибка поднята, если ключевое слово "AUTOINCREMENT" используется в
CREATE TABLE для таблицы WITHOUT ROWID. NOT NULL проведен в жизнь на каждой колонке PRIMARY KEY в WITHOUT
ROWID. Это в соответствии со стандартом SQL. Каждая колонка PRIMARY KEY,
как предполагается, является индивидуально NOT NULL. Однако, NOT NULL не был
проведен в жизнь на колонках PRIMARY KEY ранними версиями SQLite из-за
ошибки. К тому времени, когда эта ошибка была обнаружена, столько баз данных
SQLite уже было в обращении, что было принято решение не исправлять эту
ошибку из страха нарушить совместимость. Так, обычные rowid-таблицы
в SQLite нарушают стандарт SQL и позволяют NULL в поле PRIMARY KEY.
Но таблицы WITHOUT ROWID действительно следуют стандарту и бросят ошибку на
любую попытку вставить NULL в колонку PRIMARY KEY.
sqlite3_last_insert_rowid() function не работает с таблицами
WITHOUT ROWID. Вставки в WITHOUT ROWID не изменяют значение, возвращенное
функцией sqlite3_last_insert_rowid()
. last_insert_rowid()
в SQL также не затронута, так как это просто обертка вокруг
sqlite3_last_insert_rowid()
. Механизм incremental blob I/O
не работает с таблицами WITHOUT ROWID. Incremental BLOB I/O
использует rowid, чтобы создать объект
sqlite3_blob для того, чтобы сделать прямой
I/O. Однако, у таблиц WITHOUT ROWID нет rowid, и таким образом, нет никакого
способа создать объект
sqlite3_blob для таблицы WITHOUT ROWID. sqlite3_update_hook()
не обрабатывает отзывы на изменения таблиц WITHOUT ROWID. Часть отзыва от
sqlite3_update_hook() это rowid
строки таблицы, которая изменилась. Однако, у таблиц WITHOUT ROWID
как раз и нет rowid. Следовательно, перехватчик обновления не вызван, когда
изменяется таблица WITHOUT ROWID. WITHOUT ROWID это оптимизация, которая может уменьшить
место и требования к обработке. В обычной таблице SQLite PRIMARY KEY действительно просто индекс
UNIQUE.
Ключ, используемый, чтобы искать записи на диске, является
rowid.
Специальный тип колонки "
INTEGER PRIMARY KEY" в обычных таблицах SQLite
заставляет колонку быть псевдонимом для rowid, и таким образом,
INTEGER PRIMARY KEY является истинный PRIMARY KEY. Но любой другой вид
PRIMARY KEY, включая "INT PRIMARY KEY" просто уникальные
индексы в обычной таблице rowid. Предположим, что показанная выше таблица пытается
сохранить словарь слов вместе с количеством
случаев каждого слова в некотором тексте: Как обычная таблица SQLite, "wordcount"
осуществляется как два отдельных B-дерева. Главная таблица использует скрытое
значение rowid в качестве ключа и хранит столбца "word" и "cnt".
Фраза "TEXT PRIMARY KEY" в CREATE TABLE вызывает создание
уникального индекса на
столбце "word". Этот индекс это отдельное B-дерево, которое использует
"word" и "rowid" как ключ и не хранит данных вообще. Обратите внимание на то,
что полный текст каждого "word" сохранен дважды: однажды в главной
таблице и снова в индексе. Допустим, что запрос этой таблицы находит количество
случаев слова "xsync": Этот запрос сначала должен искать B-дерево индекса, ища любой вход,
который содержит совпадающее значение для "word".
Когда вход найден в индексе, rowid извлекается и используется, чтобы искать
в главной таблице. Тогда значение "cnt" прочитано и выдано.
Следовательно, два отдельных двоичных поиска требуются,
чтобы обрабатывать запрос. Таблица WITHOUT ROWID использует иной дизайн данных
для эквивалентной таблицы. В этой последней таблице есть только единственное B-дерево, которое
использует колонку "word" в качестве ее ключа и колонку "cnt"
как ее данные. Техническая особенность: внедрение низкого уровня на самом
деле хранит "word" и "cnt" в зоне "key" B-дерева. Но если вы не смотрите на
кодирование байта низкого уровня файла базы данных, этот факт неважен.
Поскольку есть только единственное B-дерево, текст колонки "word"
сохранен только однажды в базе данных. Кроме того, запрос значения
"cnt" для определенного "word" включает только единственный двоичный поиск в
главном B-дереве, так как значение "cnt" может быть получено непосредственно
из записи, найденной тем первым поиском и без потребности сделать второй
двоичный поиск на rowid. Таким образом, в некоторых случаях таблица WITHOUT ROWID
может использовать приблизительно половину суммы дискового пространства и
может работать почти вдвое шустрей. Конечно, в реальной схеме, как правило,
будут вторичные индексы и/или ограничения UNIQUE, и ситуация более сложна.
Но даже тогда часто могут быть преимущества для использования WITHOUT ROWID
для таблиц, у которых есть нецелое число или сложные PRIMARY KEY.
Оптимизация WITHOUT ROWID, вероятно, будет полезна для таблиц, у которых
есть нецелое число или сложные (многостолбцовые) PRIMARY KEY
и которые не хранят большие последовательности или BLOB. Таблицы WITHOUT ROWID будут работать правильно (то есть, они предоставляют
правильный ответ) для таблиц с единственным INTEGER PRIMARY KEY.
Однако, обычные таблицы rowid будут быстрее в этом случае.
Следовательно, хороший дизайн, чтобы избежать создавать
WITHOUT ROWID с отдельным столбцом PRIMARY KEY типа INTEGER. WITHOUT ROWID работают лучше всего, когда отдельные строки
не слишком большие. Хорошее эмпирическое правило: средний размер единственной
строки в таблице WITHOUT ROWID должен быть меньше, чем
1/20 размера страницы базы данных. Это означает, что строки
не должны содержать больше, чем приблизительно 50 байтов каждая
для размера страницы 1 кибибит или приблизительно 200 байтов каждая для
размера страницы 4 кибибита. WITHOUT ROWID будут работать (в том смысле, что
они получают правильный ответ) для произвольно больших строк,
до 2 ГБ в размере, но традиционные rowid-таблицы
имеют тенденцию работать быстрее на больших строках.
Это вызвано тем, что rowid осуществляются как
B*-Trees, где
все содержание сохранено в листьях дерева, тогда как WITHOUT ROWID
осуществляется, используя обычные B-деревья с содержанием, сохраненным на
обоих листьях и промежуточных узлах. Хранение содержания в промежуточных
узлах заставляет каждый промежуточный вход узла занимать больше места на
странице и таким образом уменьшает разветвление,
увеличивая стоимость поиска. "sqlite3_analyzer.exe", доступная как исходный код в исходном дереве
SQLite или как предварительно собранный модуль на
SQLite Download page,
может использоваться, чтобы измерить средние размеры строк таблицы в
существующей базе данных SQLite. Обратите внимание на то, что за исключением нескольких различий выше
WITHOUT ROWID и таблицы rowid работают одинаково. WITHOUT ROWID возвращает то же самое содержание для
PRAGMA table_info и
PRAGMA table_xinfo, как делает
обычная таблица. Но в отличие от обычной таблицы, WITHOUT ROWID также
отвечает PRAGMA index_info.
PRAGMA index_info на
WITHOUT ROWID возвращает информацию о PRIMARY KEY для таблицы.
Таким образом
PRAGMA index_info может использоваться, чтобы однозначно определить,
является ли конкретная таблица WITHOUT ROWID или обычной,
обычная не будет всегда возвращать строк, но WITHOUT ROWID
будет всегда возвращать одну или несколько.
Choose any three.
1. Введение
1.1. Синтаксис
CREATE TABLE IF NOT EXISTS wordcount(word TEXT PRIMARY KEY, cnt INTEGER)
WITHOUT ROWID;
1.2. Совместимость
1.3. Причуды
2.
Отличия от обычных таблиц Rowid
3.
Выгода таблиц WITHOUT ROWID
CREATE TABLE IF NOT EXISTS wordcount(word TEXT PRIMARY KEY, cnt INTEGER);
SELECT cnt FROM wordcount WHERE word='xsync';
CREATE TABLE IF NOT EXISTS wordcount(word TEXT PRIMARY KEY,
cnt INTEGER) WITHOUT ROWID;
4.
Когда использовать WITHOUT ROWID
5. Определение, если существующая таблица WITHOUT ROWID