mysql查询内连接速度慢

时间:2011-12-26 12:07:20

标签: mysql performance mysql-slow-query-log

我有以下数据库结构:

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条记录

所以,我的问题是我试图通过使用ff计算最近的业务来获得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 

有什么想让它更快?

2 个答案:

答案 0 :(得分:2)

我刚刚在MySQL手册中读到子查询可以包含ORDER BY和LIMIT。所以,我的建议如下:

将距离计算与ORDER BY和LIMIT子句一起放在单独的子查询中。然后,将您的联接放在封闭(外部)查询中。这样,您的联接操作将不会在您感兴趣的区域之外的数十万家企业中执行。

还要确保为businesscat.bizID和businesscat.catID定义了索引。

编辑:如果这不能使您的查询足够快,请尝试以下方法:

在输入查询之前,计算'min'和'max'经度和纬度(距离$ lng和$ lat的北,西,东和南100米)。然后,使用这些预过滤你的内部查询中的业务如下:WHERE business.lng >= $min_lng AND business.lng <= $max_lng AND business.lat >= $min_lat AND business.lat <= $max_lat。然后,在封闭查询中计算距离并按其重新过滤。当然,通过在business.lng和business.lat上定义索引,可以进一步优化这一点。

答案 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中使用的每个字段:

  • 距离未编入索引
  • UserID未编入索引

修改

你真的很确定,我建议你仔细查看mySQL手册。我很确定这一点,很高兴知道我现在检查了它,varchar(255)肯定与varchar(20)不同。

我认为你混淆了INT(20)=&gt; INT和Varchar(255)=&gt; VARCHAR(20)