1

我有以下数据库结构:

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 

任何想法让它更快?

4

2 回答 2

2

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

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

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

编辑:如果这不能使您的查询速度不足以满足您的目的,请尝试以下操作:

在输入查询之前,请计算“最小”和“最大”经度和纬度($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 上定义索引来进一步优化。

于 2011-12-26T12:42:37.067 回答
0

你知道你可以在 bigint 中存储多少数据吗?这足以满足整个宇宙。Smallint 或者 mediumint 都很好。

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

  • 距离未编入索引
  • 用户 ID 未编入索引

编辑

您真的确定吗,我建议您仔细检查 mySQL 手册。我对此非常确定,很高兴知道我现在检查了它并且 varchar(255) 肯定与 varchar(20) 不同。

我认为您混淆了 INT(20) => INT 和 Varchar(255) => varchar(20)

于 2011-12-26T12:54:46.807 回答