2016-02-25 3 views
-1

У меня проблема с SQLite autoindex в таблице UNIQUE. Я создаю таблицу, как показано ниже.SQLite использует autoindex вместо моего собственного индекса

c.execute('''CREATE TABLE user(
    id INTEGER PRIMARY KEY, 
    email TEXT NOT NULL UNIQUE, 
    password TEXT NOT NULL, 
    name TEXT NOT NULL, 
    );''' 
) 
c.execute('CREATE INDEX USR on user(email, password);') 

Но когда я проверяю использование плана запроса объяснения, SQLite автоматически использует autoindex. Как избежать этого, чтобы использовать мой собственный индекс вместо его автоматического индекса? Как попробовать:

c.execute('EXPLAIN QUERY PLAN SELECT id, name FROM social WHERE email = "[email protected]" AND password = 'password'') 

И resut является:

(0, 0, 0, 'SEARCH TABLE social USING INDEX sqlite_autoindex_user_1(email=?)) 

Спасибо раньше.

+0

Сколько строк в «социальных»? –

+0

Привет @ MikeSherrill'CatRecall '. Я отредактировал свой вопрос. У меня проблема с двумя таблицами, как только вы это видели, и этой отредактированной версией. Я думаю, что этот вопрос больше подходит для моего вопроса. –

+0

Хорошо. Сколько строк в «пользователе»? –

ответ

1

От the documentation:

Выбор между несколькими индексами

(...)

Столкнувшись с выбором два или более индексов, SQLite пытается оценить общее объем работы , необходимый для выполнения запроса с использованием каждой опции. Затем он выбирает опцию , которая дает наименьшую оценку работы.

Чтобы помочь оптимизатору получить более точную оценку работы , связанной с использованием различных индексов, пользователь может дополнительно выполнить команду ANSIYE . Команда ANALYZE сканирует все индексы базы данных , где может быть выбор между двумя или более индексами и собирает статистические данные об избирательности этих индексов. Статистика , собранная этим сканированием, хранится в специальных таблицах таблиц базы данных. показывает, что имена начинаются с «sqlite_stat». Содержимое этих таблиц не обновляется по мере изменения базы данных, поэтому после внесения значительных изменений может быть разумным повторить анализ ANALYZE. Результаты команды ANALYZE доступны только для соединений с базой данных, которые являются , открытыми после завершения команды ANALYZE.

(...)

Таким образом, вы можете запустить the analyze command пересканировать индексы, но это не гарантирует, что оптимизатор предпочтет индекс.

Чтобы принудительно использовать данный индекс, вы можете использовать фразу . Из the documentation:

индексированной BY фраза заставляет планировщик SQLite запроса на использование конкретного имени индекса на DELETE, SELECT или UPDATE заявление. Фраза INDEXED BY является расширением SQLite и не переносится на другие базы данных SQL.

+0

Команда ANALYZE делает запрос на большее время в моем случае. Для INDEX BY, как я сказал в других комментариях, не рекомендуется использовать в производстве. –

1

В вашем случае я считаю, что «sqlite_autoindex_user_1» - это индекс, используемый SQLite для реализации объявленного ограничения на «email». Несмотря на название, это внутренний индекс, а не autoindex.

Не путайте автоматические индексы с внутренними индексами (имеющих имена, как «sqlite_autoindex_table_N»), которые иногда создаются для реализации PRIMARY KEY или ограничение уникальности. Описанные здесь автоматические индексы существуют только для продолжительности одного запроса, никогда не сохраняются на диске и видны только для одной базы данных. . Внутренние индексы являются частью реализации PRIMARY Ограничения KEY и UNIQUE, долговечны и сохраняются на диске, и видны для всех подключений к базе данных. Термин «autoindex» появляется в названиях внутренних индексов по унаследованным причинам, и не указывает, что внутренние индексы и автоматические индексы связаны.

Source

Оптимизатор решил, что с помощью индекса на «электронной почты» будет самым быстрым. Вероятно, это правильно.


Чтобы посмотреть, как SQLite может использовать ваш индекс покрытия «medp», создайте тестовую таблицу, подобную этой.

create table social_test (
    id integer primary key, 
    name text not null, -- no UNIQUE constraint for testing 
    tampil integer not null 
); 

create index medp on social (name, tampil); 

Вставьте миллион строк, если хотите.

analyze social; 
explain query plan select * from social where name = 'facebook' and tampil = 6; 
0|0|0|SEARCH TABLE social USING COVERING INDEX medp (name=? AND tampil=?) 
+0

ANALYZE сам занимает несколько раз, поэтому запрос больше. Правильно ли запускать ANALYZE в каждом подключении к базе данных или запускать только один раз для нового подключения? –

+0

@ChristoforusSurjoputro: вам нужно всего лишь запустить ANALYZE, когда содержимое базы данных сильно изменится (я добавил миллион строк), когда изменяется схема, или когда вы просто хотите, чтобы статистика была актуальной, прежде чем рассматривать планы запросов. –

2

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

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

Чтобы заставить базу данных использовать ваш индекс, вы можете использовать INDEXED BY clause, но это не улучшит производительность.

+0

Вы правы, когда принудительно использовать sqlite для использования другого индекса с помощью предложения INDEX BY, но его не рекомендуется использовать в процессе производства. –

2

А вот здесь несколько проблем.

  1. Первый оператор SQL (CREATE TABLE ...) имеет неверный формат из-за дополнительную запятую между последней колонкой и закрывающей скобкой.

  2. Третий оператор SQL (EXPLAIN QUERY PLAN SELECT ...) использует двойные кавычки вокруг указанного адреса электронной почты. SQLite позволит это для соображений обратной совместимости, но это не рекомендуется.

  3. Цитирование строки, представляющей третий оператор SQL, неправильно цитируется на любом языке, с которым я знаком.

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

Если мы предположим, что вы имели в виду «пользователь», когда вы ввели «social», как CL. сказал, что «autoindex» в использовании гарантирует, что электронная почта уникальна, поэтому ей ничего не нужно.Он мог бы использовать ваш явный индекс как индекс покрытия, если вам не нужен также столбец имен, но поскольку ваш явный индекс не включает столбец имен (в соответствии с требованием оператора select), он считает, что autoindex лучше. Кроме того, autoindex почти наверняка лучше для этого случая, потому что меньший индекс (только адрес электронной почты с адресом электронной почты &) означает, что, вероятно, будет меньше читаемых страниц btree при попытке найти запрошенный адрес электронной почты. Другими словами, индекс только для адреса электронной почты будет меньшим индексом, чем индекс по электронной почте и паролю.

Смежные вопросы