Эффективный выбор / порядок MySQL для запроса диапазона с несколькими индексами / столбцами - PullRequest
1 голос
/ 23 декабря 2009

Я пытаюсь сделать наиболее эффективный выбор для таблицы с 3 миллионами записей.

Сначала немного подробной информации

Таблица:

CREATE TABLE IF NOT EXISTS `activities_index` (
  `id` int(9) NOT NULL auto_increment,
  `activity_id` int(6) NOT NULL,
  `activity_status_id` int(2) NOT NULL,
  `activity_source_id` int(6) default NULL,
  `account_id` int(6) default NULL,
  `owner_account_id` int(4) default NULL,
  `date` date NOT NULL,
  `is_event` int(1) NOT NULL,
  `name` varchar(255) collate utf8_unicode_ci NOT NULL,
  `content` longtext collate utf8_unicode_ci,
  `location_name` varchar(255) collate utf8_unicode_ci default NULL,
  `location_content` longtext collate utf8_unicode_ci,
  `meta_keywords` varchar(255) collate utf8_unicode_ci default NULL,
  `thumb_filename` varchar(255) collate utf8_unicode_ci default NULL,
  `popular` int(1) NOT NULL default '0',
  `price` float default NULL,
  `city_id` int(9) default NULL,
  `province_id` int(4) default NULL,
  `country_id` int(4) default NULL,
  `activity_location_id` int(6) NOT NULL,
  `lat` decimal(10,6) default NULL,
  `lng` decimal(10,6) default NULL,
  `activity_modified` datetime default NULL,
  `activity_created` datetime NOT NULL,
  `activity_location_modified` datetime default NULL,
  `activity_location_created` datetime NOT NULL,
  `modified` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`id`),
  KEY `is_event_idx` (`is_event`),
  KEY `activity_id_idx` (`activity_id`),
  KEY `status_city_idx` (`activity_status_id`, `city_id`),
  KEY `date_idx` (`date`),
  FULLTEXT KEY `txt_fields_idx` (`name`,`location_name`,`meta_keywords`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=14865 ;

Запрос:

SELECT SQL_NO_CACHE * FROM `activities_index` WHERE 
date BETWEEN '2009-12-23' AND '2010-1-23' AND
activity_status_id = 1 AND
city_id IN ('86', '84', '87', '2381', '453', '137', '1561', '1116', '1614', '2456', '512', '305', '443', '1182', '2229')
ORDER BY date
LIMIT 25

О моем выборе индекса:
Основная проблема - выбор диапазона по ДАТЕ. Почему я не использую многостолбцовый индекс, основываясь на том, что считаю верным, пожалуйста, исправьте меня, если я ошибаюсь: MySQL не использует индексы после диапазона. Таким образом, индекс (DATE, ACTIVITY_STATUS_ID, CITY_ID) будет бесполезным. Порядок в таблице индексов является правильным только при использовании правильного префикса. Поэтому индекс нескольких столбцов (CITY_ID, ACTIVITY_STATUS_ID, DATE) не даст правильного упорядоченного результата, поскольку мы хотим упорядочить данные в столбце DATE.

Объясните:
При выполнении EXPLAIN для запроса порядок возможных_ключей - CITY_IDX, вместо этого DATE_STATUS_IDX, я думаю, что переключение этого порядка в DATE_IDX, CITY_IDX будет более эффективным при упорядочении по DATE.

id  select_type  table  type  possible_keys  key  key_len  ref  rows  Extra<br />
1  SIMPLE  activities_index  range  city_idx,date_idx  city_idx  5  NULL  1363  Using where; Using filesort

Мои вопросы:
Как мне изменить порядок возможных ключей?
Есть ли лучший способ решения проблемы: эффективный выбор таблицы с 3 миллионами записей?
Мой образ мышления правильный?

Ответы [ 3 ]

0 голосов
/ 23 декабря 2009

Я сейчас думаю о чем-то совершенно ином. Поскольку city_ids являются результатом диапазона base_city +, можно было бы использовать только дату плюс алгоритм в предложении where для определения расстояния действия base_city ->. Это займет около 0,009 сек. Недостатком является использование того, что мы иногда все еще используем city_ids. Хм.

SQL_NO_CACHE *
FROM `activities_index` AS idx
WHERE 
ROUND(
((acos(sin((52.220818*pi()/180)) * sin(( idx.lat *pi()/180)) + cos((52.220818*pi()/180)) * cos(( idx.lat *pi()/180)) * cos(( (6.891140 -  idx.lng )*pi()/180 )))) 
*180/pi()) *60*1.1515*1.609344
) < 15 AND idx.date BETWEEN '2009-12-23' AND '2010-1-23'
ORDER BY idx.date
LIMIT 25
0 голосов
/ 24 декабря 2009

Немного интересной информации о объединении индекса . К сожалению, ваш запрос является прекрасным примером одного из перечисленных недостатков (сканирование по одному диапазону).

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

Примечание: порядок возможных_ключей в выводе EXPLAIN не имеет значения. Ваша формулировка также звучит так, как будто вы интерпретируете вывод EXPLAIN, чтобы сказать, что он выбирает диапазон, используя date. Это не. Он делает выбор диапазона для city_id (он будет сканировать каждую строку со значением city_id между минимальным и максимальным значениями в предложении IN(). Эффективность этого будет сильно зависеть от распределения ваших значений.

Вы пытались запустить ANALYZE TABLE activities_index, чтобы увидеть, изменяется ли скорость запроса и / или вывод EXPLAIN. MySQL часто пытается предсказать распределение значений на основе типа столбца, но на самом деле анализ таблицы дает истинное распределение для использования, которое может позволить ему лучше выбрать лучшие ключи.

0 голосов
/ 23 декабря 2009

Насколько я помню, sql-query-analyzer анализирует запрос справа налево - поэтому первый индекс, который он встречает, - это город, потому что он самый правильный. может быть, вы можете перевернуть индексы, изменив положение входных и промежуточных предложений. Вам нужна вся информация с вашего стола? в противном случае вы могли бы набрать скорость, выбрав только нужные вам столбцы.

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