оптимизация производительности mysql для подзапроса в предложении select - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть 2 таблицы (companies и companies_locations) и очень простой запрос

SELECT 
  c.name, 
  (SELECT MIN(ST_Distance_Sphere(l.coords, POINT(4.985173, 45.001672)) from companies_locations l where l.companyId = c.id
FROM companies c
WHERE MATCH (c.name) AGAINST ('+rand*' IN BOOLEAN MODE) 

Примечание: долгота, широта и полный текст задаются через параметры в моем коде

Примечание: там может бытьбыть множеством companies_locations для данной компании (отсюда минимум и подзапрос)

Теперь моя проблема: Я не понимаю, почему mysql не может использовать индекс покрытия для companies_locations (companyId, ords)

Вот подробности sql:

drop table IF exists companies;
drop table IF exists companies_locations;

CREATE TABLE `companies` (
  `id` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
  `name` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  FULLTEXT KEY `idx_ft_provider_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE `companies_locations` (
  `id` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
  `companyId` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
  `coords` point DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_providerId` (`companyId`,`coords`(25)),
  KEY `idx_providerIdCoords` (`companyId`,`coords`(25))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

INSERT INTO companies (id, name) ...;
INSERT INTO companies_locations (id, companyId, coords) ...;

explain SELECT 
      c.name, 
      (SELECT MIN(ST_Distance_Sphere(l.coords, POINT(4.985173, 45.001672))) from companies_locations l where l.companyId = c.id) as dist
    FROM companies c
    WHERE MATCH (c.name) AGAINST ('+rand*' IN BOOLEAN MODE) 

План объяснения:

'1', 'PRIMARY', 'c', NULL, 'fulltext', 'idx_ft_provider_name', 'idx_ft_provider_name', '0', 'const', '1', '100.00', 'Using where; Ft_hints: no_ranking'
'2', 'DEPENDENT SUBQUERY', 'l', NULL, 'ref', 'idx_providerId,idx_providerIdCoords', 'idx_providerId', '162', 'beasyness.c.id', '1', '100.00', NULL

В ЗАВИСИМОЙ ПОДПИСИ я бы хотел, чтобы оптимизаторвыберите idx_providerIdCoords и «Using index: true»

Даже если я удаляю другой индекс, оптимизатор, похоже, по-прежнему делает «простую» ссылку (т.е. нужно перейти к таблице, чтобы прочитать координаты)

1 Ответ

0 голосов
/ 04 марта 2019

Почти во всех случаях MySQL запускается, когда обнаруживает «индекс префикса» (INDEX(..., coords(25)). В частности, он не может требовать «использования индекса», поскольку индекс не «покрывает». То есть ему могут потребоваться байты послепервые 25.

Поскольку idx_providerIdCoords и idx_providerId идентичны, не следует ожидать, что Оптимизатор будет использовать один вместо другого.

Следующие могут бытьоптимизация для вашего случая. Измените

PRIMARY KEY (`id`),
KEY `idx_providerId` (`companyId`,`coords`(25)),
KEY `idx_providerIdCoords` (`companyId`,`coords`(25))

на

PRIMARY KEY(`companyId`,`coords`),
KEY (`id`)

Это "кластеры" на companyId (плюс coords), таким образом, поместив все местоположения для данной компании«рядом» друг с другом в таблице. Однако он разделяет значения id. (Как, черт возьми, выглядит id VARCHAR(40)?)

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