我有以下数据库结构:
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
有什么想让它更快?
答案 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中使用的每个字段:
修改强>
你真的很确定,我建议你仔细查看mySQL手册。我很确定这一点,很高兴知道我现在检查了它,varchar(255)肯定与varchar(20)不同。
我认为你混淆了INT(20)=&gt; INT和Varchar(255)=&gt; VARCHAR(20)