У меня есть база данных с 3 таблицами.
CREATE TABLE `records` (
`id` int(6) NOT NULL auto_increment,
`nu` varchar(40) NOT NULL UNIQUE,
`name` varchar(128),
`latitude` float NOT NULL,
`longitude` float NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `categories` (
`category_id` int(11) NOT NULL,
`category_label` varchar(100) NOT NULL UNIQUE,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `relational` (
`r_id` int(6) NOT NULL auto_increment,
`id` int(6) NOT NULL,
`category_id` int(11) NOT NULL auto_increment,
PRIMARY KEY (`r_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Также у меня есть 2 внешних ключа, category_id и id.
Я сделал индекс для category_label и latitude тоже.
Я сделал мой запрос так
SELECT id, name, latitude, longitude, category_label, ( 6371 * acos( cos(
radians('$lat') ) * cos( radians( latitude ) ) * cos( radians( longitude ) -
radians('$lng') ) + sin( radians('$lat') ) * sin( radians( latitude ) ) ) )
AS distance, FROM records JOIN relational ON records.id = relational.id
JOIN categories ON relational.category_id = categories.category_id
WHERE category_label = '$label' GROUP BY distance HAVING (distance <=
'$radius') ORDER BY distance
Моя проблема в том, что у меня большая база данных, и выполнение запроса занимает слишком много времени. Какие индексы я должен использовать для этого запроса. На самом деле я не знаю, какой правильный способ иметь индексы, которые помогут мне с расстоянием. Должен ли я изменить индексы? Как я могу улучшить свою структуру БД или мой запрос? Я использую InnoDB.
Прежде всего, вы, вероятно, должны взглянуть на этот а также этот — Я настоятельно рекомендую использовать его вместо общих типов данных в вашем случае.
Что касается вашей текущей схемы, рассмотрите возможность добавления индексов на relational.id
а также relational.category_id
(2 отдельных индекса). Но это не поможет в долгосрочной перспективе. Другое дело, что поможет — не рассчитывать distance
на лету — кэшируйте его в другой таблице, например, где вы можете проиндексировать его: одна из самых дорогих частей вашего запроса — группировка и пост-фильтрация в динамическом (а значит, медленном) поле
И вам не нужен еще один индекс для categories.category_label
— у вас уже есть уникальное ограничение, что подразумевает индексирование.
Вы также можете создать индекс покрытия на вашем records
таблицы, но это не даст большой поддержки по сравнению с исправлением динамических полевых операций
Чтобы помочь начать в categories
, добавлять INDEX(category_label)
relational
выглядит как сопоставление «многие ко многим». Находятся ли «записи» в нескольких «категориях», и в каждой «категории» есть много «записей»? Если так, то многим ко многим нужно. Для повышения производительности следуйте советам Вот .
Затем…
Быстрый и простой способ улучшить поиск расстояния — это иметь «ограничивающий прямоугольник» в WHERE
пункт и есть INDEX(latitude), INDEX(longitude)
,
Если nu
является UNIQUE
тогда вам, вероятно, следовало бы PRIMARY KEY
и избавиться, если id
, (Изменить Relational
первый.)
Следующая проблема заключается в том, что фильтрация (WHERE
) попадает в две таблицы (для фильтрации по категории и по местоположению). Такое нельзя оптимизировать. Вместо этого надежда состоит в том, что запрос может эффективно фильтровать одну таблицу, а затем улучшать ее при просмотре другой таблицы.
Google пространственный индекс. Это двумерная индексация для данных геометрии.