Mysql не использует мои индексы - PullRequest
0 голосов
/ 10 июня 2009

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

Может ли кто-нибудь взглянуть и дать мне подсказку, чего мне не хватает?

Моя база данных - MyISAM, и я использую Mysql 5.1, PHP5

Вот мой стол:

--
-- Table structure for table `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` bigint(20) NOT NULL auto_increment,
  `name` varchar(40) default NULL,
  `city` varchar(90) default NULL,
  `latitude` float NOT NULL default '0',
  `longitude` float NOT NULL default '0',
  PRIMARY KEY  (`user_id`),
  UNIQUE KEY `name` (`name`),
  KEY `Radius Search` (`latitude`,`longitude`),
  KEY `Radius 2` (`longitude`,`latitude`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=38666 ;

Вот мой запрос:

$query =    
"SELECT
    name, city
FROM
    users
WHERE
    (
        (69.1 * (latitude - " . $user->latitude . ")) * 
        (69.1 * (latitude - " . $user->latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3))
    ) < " . pow($radius, 2) . " 
ORDER BY 
    (
        (69.1 * (latitude - " . $user->latitude . ")) * 
        (69.1 * (latitude - " . $user->latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3))
    ) ASC";

И, наконец, мое объяснение ...

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  users   ALL     NULL    NULL    NULL    NULL    38665   Using where; Using filesort

Ответы [ 3 ]

3 голосов
/ 10 июня 2009

Как именно предполагается использовать отсортированный индекс по «широте» для более эффективной оценки вашего предложения where? ... Когда поле используется в выражении в предложении where, индексы обычно не применяются.

Более того, в этом случае я не уверен, что вы даже можете переписать предложение, чтобы применить индекс, что немного реже.

Добавление
Глядя на то, что вы на самом деле пытаетесь сделать, возможно, вы можете использовать поле lat / long фиксированного размера вокруг координат пользователя, чтобы вы могли использовать предложения BETWEEN для lat и long. Тогда вы можете оставить комплекс ORDER BY таким, какой он есть сейчас, и обрезать после 'x' ближайших других пользователей.

Тогда вы можете никогда не заметить, что спички на самом деле находятся в прямоугольнике, а не в круговом радиусе от того, который вы рассматриваете.

2 голосов
/ 10 июня 2009

Вы на самом деле ничего не сравниваете с широтой или долготой. Для работы индесов необходимо выполнить что-либо в mysql с широтой = (или <> между и т. Д.).

Попробуйте переписать запрос так, чтобы он читал

ГДЕ широта между $ lat_low AND $ lat_hi и долгота между $ long_low AND $ long_hi

2 голосов
/ 10 июня 2009

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

Индексы MySQL по столбцам, а не по выражениям. У вас есть несколько вариантов здесь:

  1. Можете ли вы свести выражение к фиксированному значению и сохранить его в одном или двух столбцах?

Если это невозможно, рассмотрите возможность создания очень быстрой таблицы поиска и присоединитесь к ней. Например:

CREATE TABLE user_loc 
(
    longitude float(n,m) not null, 
    latitude float(n,m) not null, 
    user_id int unsigned not null
);

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

(примечание: проверьте требования к производительности, прежде чем переходить к этим значениям, так как они могут вам вообще не понадобиться)

...