使用子查询内部优化此MySQL查询

时间:2016-10-12 03:58:38

标签: mysql sql database query-optimization

对于给定的经度,纬度和半径,我应该从具有500&#39,000个数据记录的数据库中选择averagePrice,numberOfListings,....

  

(id)1(select_type)SIMPLE(表)数据库(分区)NULL(类型)ALL(possible_keys)NULL(键)NULL(key_len)NULL(ref)NULL(行)623612(已过滤)100.00(额外) NULL

CREATE TABLE `database` (
  `id` varchar(255) DEFAULT NULL,
  `longitude` varchar(255) DEFAULT NULL,
  `latitude` varchar(255) DEFAULT NULL,
  `price` int(11) DEFAULT NULL,
  `bathrooms` int(11) DEFAULT NULL,
  `bedrooms` int(11) DEFAULT NULL,
  `person_capacity` int(11) DEFAULT NULL,
  `rev_count` int(11) DEFAULT NULL,
  KEY `hosting_id` (`hosting_id`),
  KEY `price` (`price`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

选择不分组的查询。

SELECT
   avg(price) as averagePrice,
   count(*) as numberOfListings,
   min(price) as minprice,
   max(price) as maxprice,
   avg(bedrooms) as averagebedrooms,
   avg(bathrooms) as averagebathrooms,
   avg(person_capacity) as averagepc,
   avg(rev_count) as averageReviews,
   avg(time_appartement) as averageDateHasBeenListed  
FROM
   (SELECT
      r.*,
      ( 6371 * acos( cos( radians(37.774929) ) * cos( radians( ANY_VALUE(`latitude` )) ) * cos( radians( ANY_VALUE(`longitude`) ) - radians(-122.419416) ) + sin( radians(37.774929) ) * sin( radians( ANY_VALUE(`latitude`) ) ) ) ) AS distance        
   FROM
      `database` r       ) r  
WHERE
   distance <= 25 
   AND price >= 10  
ORDER BY
   distance ASC

这适用于查询时间约1秒。现在我接下来的步骤是将子查询与id分组,并为每个id选择平均价格,卧室,浴室,person_capacity,rev_count和time_appartement。

SELECT
   avg(price) as averagePrice,
   count(*) as numberOfListings,
   min(price) as minprice,
   max(price) as maxprice,
   avg(bedrooms) as averagebedrooms,
   avg(bathrooms) as averagebathrooms,
   avg(person_capacity) as averagepc,
   avg(rev_count) as averageReviews,
   avg(time_appartement) as averageDateHasBeenListed      
FROM
   (SELECT
      id,
      avg(r.price) as price,
      avg(r.bedrooms) as bedrooms,
      avg(r.bathrooms) as bathrooms,
      avg(r.person_capacity) as person_capacity,
      avg(r.rev_count) as rev_count,
      avg(r.time_appartement) as time_appartement,
      ( 6371 * acos( cos( radians(37.774929) ) * cos( radians( ANY_VALUE(`latitude` )) ) * cos( radians( ANY_VALUE(`longitude`) ) - radians(-122.419416) ) + sin( radians(37.774929) ) * sin( radians( ANY_VALUE(`latitude`) ) ) ) ) AS distance            
   FROM
      `database` r 
   GROUP BY
      r.id           ) r      
WHERE
   distance <= 25 
   AND price >= 10      
ORDER BY
   distance ASC

它有效,但问题是这个查询的时间大约是7秒。

是否可以减少时间? 谢谢你的回复。

2 个答案:

答案 0 :(得分:0)

您可以将价格条件移至子查询。

  • 如果你只考虑价格&gt; = 10(计算平均值之前)的记录,那么r.price&gt; = 10
  • 如果您考虑平均价格&gt; = 10
  • ,请使用平均价格(r.price)&gt; = 10

另外,请确保您拥有ID和价格索引

答案 1 :(得分:0)

latitudelongitudeVARCHAR(255)更糟糕。对于家庭来说,这应该是好的:

latitude DECIMAL(6,4),
longitude DECIMAL(7,4)

什么样的id需要VARCHAR(255)

你期待数百万或数十亿的卧室吗?使用TINYINT UNSIGNED(1个字节,范围为0..255)可以提高效率。

没有PRIMARY KEY;这对InnoDB来说很糟糕。

AVG(AVG(...))在数学上是不好的。

您的子查询意味着有多个行具有相同的id;发生了什么事?

修复这些内容,阅读&#34;边界框&#34;然后再回来寻求更多帮助/滥用。