2011-12-26 5 views
1

У меня есть следующая структура базы данных:MySQL запросов внутреннее соединение замедляя

CREATE TABLE IF NOT EXISTS `business` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `address` varchar(255) NOT NULL, 
    `city` varchar(255) NOT NULL, 
    `state` varchar(255) NOT NULL, 
    `postal` int(11) NOT NULL, 
    `country` varchar(255) NOT NULL, 
    `lat` float NOT NULL, 
    `lng` float NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `phone` varchar(255) NOT NULL, 
    `email` varchar(255) NOT NULL, 
    `website` varchar(255) NOT NULL, 
    `userID` bigint(20) NOT NULL, 
    `url` varchar(255) NOT NULL, 
    `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `clicks` bigint(20) NOT NULL, 
    `oHours` varchar(255) NOT NULL, 
    `featured` tinyint(1) NOT NULL, 
    `imageThumb` varchar(255) NOT NULL DEFAULT 'default.jpg', 
    `imageOrig` varchar(255) NOT NULL DEFAULT 'default.jpg', 
    `flag` tinyint(1) NOT NULL, 
    `display` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=589846 ; 

Эта таблица (бизнес) имеет 507,736 записей

CREATE TABLE IF NOT EXISTS `businesscat` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `bizID` bigint(20) NOT NULL, 
    `catID` bigint(20) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=589863 ; 

Эта таблица (businesscat) имеет 519,825 записей

CREATE TABLE IF NOT EXISTS `category` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(255) NOT NULL, 
    `url` varchar(255) NOT NULL, 
    `icon` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ; 

В этой таблице (категории) всего 5 записей

Итак, моя проблема, я пытаюсь получить 100 записей с расчетом ближайшего бизнеса с помощью ФФ:

SELECT business.name 
, business.lng 
, business.lat 
, business.address 
, business.city 
, business.state 
, business.postal 
, business.phone 
, business.url 
, business.imageThumb 
, businesscat.catID 
, category.icon 
, (((acos(sin((".$lat."*pi()/180)) 
    * sin((business.lat*pi()/180)) 
    + cos((".$lat."*pi()/180)) 
    * cos((business.lat*pi()/180)) 
    * cos(((".$lng."-business.lng)*pi()/180)))) 
    * 180/pi())*60*1.1515) AS distance 
FROM business 
INNER JOIN businesscat ON businesscat.bizID=business.id 
INNER JOIN category ON category.id=businesscat.catID 
ORDER BY distance LIMIT 100 

Любая идея, чтобы сделать это быстрее?

+0

Я предполагаю, что все работает нормально, если оставить заказ по расстоянию? – rene

+1

Вы указали индексы для businesscat.bizID и businesscat.catID? Кроме того, вы можете оптимизировать таблицу businesscat, отбросив id и объявив bizID и catID в качестве первичного ключа, хотя я сомневаюсь, что это улучшит ваш запрос. –

+0

«Быстрее» чем? –

ответ

2

Я только что прочитал в руководстве MySQL, что подзапросы могут содержать ORDER BY и LIMIT. Таким образом, мое предложение было бы следующим:

Рассчитайте расчет расстояния в отдельном подзапросе вместе с предложениями ORDER BY и LIMIT. Затем добавьте свои соединения в закрытый (внешний) запрос. Таким образом, операции ваших объединений не будут выполняться для сотен тысяч компаний, которые не за пределами вашей области интересов для начала.

Также убедитесь, что вы указали индексы для businesscat.bizID и businesscat.catID.

EDIT:, если это не делает запрос достаточно быстро для ваших целей, то попробуйте следующее:

Перед входом запроса, вычислить «мин» и долготы и широты «Макс» (100 метров к северу, западу, востоку и к югу от ваших $ lng и $ lat.) Затем используйте их для предварительной фильтрации ваших предприятий во внутреннем запросе следующим образом: WHERE business.lng >= $min_lng AND business.lng <= $max_lng AND business.lat >= $min_lat AND business.lat <= $max_lat. Затем в прилагаемом запросе вычисляем расстояние и повторно фильтруем его. И, конечно, это может быть еще более оптимизировано путем определения индексов на business.lng и business.lat.

+0

+1 для вас ...... –

0

Знаете ли вы, сколько данных вы можете хранить в bigint? Этого хватит для всей вселенной. Smallint или, возможно, средний уровень - это хорошо.

All of the fields have varchar(255)! do you really need that much data? 

Вы можете кэшировать план выполнения запросов mySQL, используете ли вы это? хранения двигателей

ваши таблицы являются InnoDB, поэтому позвольте мне задать вам более важный вопрос:

Do you use innodb_file_per_table setting? 

индекса каждое поле, которое используется в ORDER BY или в JOINS:

  • расстояние не индексированный
  • Идентификатор_пользователя не индексируется

EDIT

Вы действительно уверены в этом, я рекомендую вам дважды проверить руководство mySQL.Я очень уверен в этом, и хорошо знать, что я проверил его сейчас, и varchar (255), безусловно, отличается от varchar (20).

Я думаю, вы путать INT (20) => INT и Varchar (255) => VARCHAR (20)

+0

"_var_ char". Неважно, какой максимум, в частности. http://forums.mysql.com/read.php?24,105964,105964 –

+0

Я проверил его сейчас, и MySQL перекосил мои данные в то, что я указал! – ALH

+0

Да, я использую параметр innodb_file_per_table. Я уже проиндексировал bizID и catID. То же самое, очень медленно. –

Смежные вопросы