MySQL оптимизация запросов — индексы

У меня есть база данных с 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.

0

Решение

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

Что касается вашей текущей схемы, рассмотрите возможность добавления индексов на relational.id а также relational.category_id (2 отдельных индекса). Но это не поможет в долгосрочной перспективе. Другое дело, что поможет — не рассчитывать distance на лету — кэшируйте его в другой таблице, например, где вы можете проиндексировать его: одна из самых дорогих частей вашего запроса — группировка и пост-фильтрация в динамическом (а значит, медленном) поле

И вам не нужен еще один индекс для categories.category_label — у вас уже есть уникальное ограничение, что подразумевает индексирование.

Вы также можете создать индекс покрытия на вашем records таблицы, но это не даст большой поддержки по сравнению с исправлением динамических полевых операций

0

Другие решения

  1. Чтобы помочь начать в categories, добавлять INDEX(category_label)

  2. relational выглядит как сопоставление «многие ко многим». Находятся ли «записи» в нескольких «категориях», и в каждой «категории» есть много «записей»? Если так, то многим ко многим нужно. Для повышения производительности следуйте советам Вот .

  3. Затем…

Быстрый и простой способ улучшить поиск расстояния — это иметь «ограничивающий прямоугольник» в WHERE пункт и есть INDEX(latitude), INDEX(longitude),

Если nu является UNIQUEтогда вам, вероятно, следовало бы PRIMARY KEY и избавиться, если id, (Изменить Relational первый.)

Следующая проблема заключается в том, что фильтрация (WHERE) попадает в две таблицы (для фильтрации по категории и по местоположению). Такое нельзя оптимизировать. Вместо этого надежда состоит в том, что запрос может эффективно фильтровать одну таблицу, а затем улучшать ее при просмотре другой таблицы.

0

Google пространственный индекс. Это двумерная индексация для данных геометрии.

0
По вопросам рекламы [email protected]