优化SQL语句

时间:2010-04-01 10:04:37

标签: sql mysql

嘿,我正在运行WordPress,数据库图可以在这里找到:http://codex.wordpress.org/Database_Description

在完成大量过滤器并将一些钩子应用到核心后,我留下了以下查询:

SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts 

JOIN wp_postmeta ppmeta_beds ON (ppmeta_beds.post_id = wp_posts.ID AND
  ppmeta_beds.meta_key = 'pp-general-beds' AND ppmeta_beds.meta_value >= 2)

JOIN wp_postmeta ppmeta_baths ON (ppmeta_baths.post_id = wp_posts.ID AND
  ppmeta_baths.meta_key = 'pp-general-baths' AND ppmeta_baths.meta_value >= 3)

JOIN wp_postmeta ppmeta_furnished 
  ON (ppmeta_furnished.post_id = wp_posts.ID AND
  ppmeta_furnished.meta_key = 'pp-general-furnished' 
  AND ppmeta_furnished.meta_value = 'yes')

JOIN wp_postmeta ppmeta_pool 
  ON (ppmeta_pool.post_id = wp_posts.ID AND
  ppmeta_pool.meta_key = 'pp-facilities-pool' 
  AND ppmeta_pool.meta_value = 'yes')

JOIN wp_postmeta ppmeta_pool_type 
  ON (ppmeta_pool_type.post_id = wp_posts.ID AND
  ppmeta_pool_type.meta_key = 'pp-facilities-pool-type' 
  AND ppmeta_pool_type.meta_value 
  IN ('tennis', 'voleyball', 'basketball', 'fitness'))

JOIN wp_postmeta ppmeta_sport ON (ppmeta_sport.post_id = wp_posts.ID AND
  ppmeta_sport.meta_key = 'pp-facilities-sport' 
  AND ppmeta_sport.meta_value = 'yes') 

JOIN wp_postmeta ppmeta_sport_type ON (ppmeta_sport_type.post_id = wp_posts.ID 
  AND ppmeta_sport_type.meta_key = 'pp-facilities-sport-type' 
  AND ppmeta_sport_type.meta_value 
  IN ('tennis', 'voleyball', 'basketball', 'fitness')) 

JOIN wp_postmeta ppmeta_parking ON (ppmeta_parking.post_id = wp_posts.ID 
  AND ppmeta_parking.meta_key = 'pp-facilities-parking' 
  AND ppmeta_parking.meta_value = 'yes') 

JOIN wp_postmeta ppmeta_parking_type 
  ON (ppmeta_parking_type.post_id = wp_posts.ID 
  AND ppmeta_parking_type.meta_key = 'pp-facilities-parking-type' 
  AND ppmeta_parking_type.meta_value IN ('street', 'off-street', 'garage')) 

JOIN wp_postmeta ppmeta_garden ON (ppmeta_garden.post_id = wp_posts.ID 
  AND ppmeta_garden.meta_key = 'pp-facilities-garden' 
  AND ppmeta_garden.meta_value = 'yes') 

JOIN wp_postmeta ppmeta_garden_type 
  ON (ppmeta_garden_type.post_id = wp_posts.ID 
  AND ppmeta_garden_type.meta_key = 'pp-facilities-garden-type' 
  AND ppmeta_garden_type.meta_value IN ('private', 'communal')) 

JOIN wp_postmeta ppmeta_type ON (ppmeta_type.post_id = wp_posts.ID 
  AND ppmeta_type.meta_key = 'pp-general-type' 
  AND ppmeta_type.meta_value IN ('villa', 'apartment', 'penthouse')) 

JOIN wp_postmeta ppmeta_status ON (ppmeta_status.post_id = wp_posts.ID 
  AND ppmeta_status.meta_key = 'pp-general-status' 
  AND ppmeta_status.meta_value IN ('off-plan', 'resale')) 

JOIN wp_postmeta ppmeta_location_type 
  ON (ppmeta_location_type.post_id = wp_posts.ID 
  AND ppmeta_location_type.meta_key = 'pp-location-type' 
  AND ppmeta_location_type.meta_value 
  IN ('beachfront', 'countryside', 'town-center', 'near-the-sea', 
    'hillside', 'private-resort')) 

JOIN wp_postmeta ppmeta_price_range 
  ON (ppmeta_price_range.post_id = wp_posts.ID 
  AND ppmeta_price_range.meta_key = 'pp-general-price' 
  AND ppmeta_price_range.meta_value BETWEEN 10000 AND 50000) 

JOIN wp_postmeta ppmeta_area_range 
  ON (ppmeta_area_range.post_id = wp_posts.ID 
  AND ppmeta_area_range.meta_key = 'pp-general-area' 
  AND ppmeta_area_range.meta_value BETWEEN 50 AND 150) 

WHERE 1=1 AND (((wp_posts.post_title LIKE '%fdsfsad%') 
OR (wp_posts.post_content LIKE '%fdsfsad%'))) 
AND wp_posts.post_type = 'property' 
AND (wp_posts.post_status = 'publish' 
  OR wp_posts.post_status = 'private') 
ORDER BY wp_posts.post_date DESC LIMIT 0, 10

这太大了。有人可以告诉我一种优化所有这些连接的方法吗?正如您所看到的,它们都使用相同的表但名称不同。我不是一个SQL大师,但我认为应该有办法,因为这是疯了;)

谢谢!

更新以下是返回的解释:http://twitpic.com/1cd36p

4 个答案:

答案 0 :(得分:2)

你不能优化它。您需要所有连接,因为它们是单独的过滤器,可能是由于AND逻辑,即您需要海滨和街边停车。

您最好的办法是确保您的餐桌不会分散。拥有元值,元键和后id的索引。

答案 1 :(得分:1)

PHP通过自己的协议连接到mysql。允许的SQL大小上升了MB,因为php / mysql通信在localhost(或局域网)上,它不会成为瓶颈。所以,在php amd mysql之间的通信方面,SQL的大小并不重要。

在准备SQL(解析和规划)方面,它可能需要额外的时间,您可以考虑创建一个执行上述操作的VIEW。

此外,重要的是索引,但计划看起来没问题(除了filesort - 您可能希望有一个可用于排序和选择wp_post的索引)。

此外,您只从wp_post表中选择列,但正在加入更多表 - 考虑使用WHERE EXISTS条件重写它。

至于优化 - 确实在数据库中获得一些样本数据,这些样本数据将模拟最终打算拥有的数据库的硬件和大小。优化查询是您在开发过程中不应忘记的事情,但过早花费太多时间可能是不合理的。

答案 2 :(得分:1)

这是实现基于属性的搜索的一种特别低效的方式。不幸的是我不知道WordPress是否可以通过其他任何方式实现它,即:每个属性都应该有自己的列和索引。这不太灵活,但速度更快。

答案 3 :(得分:1)

正如Simon Sabin已经说过你无法摆脱连接,因为它们可以作为过滤器使用。

为了阅读目的,将wp_postmeta上的索引设为(post_id,meta_key,metavalue(255))会很棒。顺序很重要,因为按顺序会评估连接中的条件,但索引会使数据库的大小加倍并减慢插入和更新的速度。

应用产品集条件的顺序也不是最优的:方程式应先行,然后是LIKE和范围条件,否则不会使用索引进行过滤。

最后但并非最不重要的杀手是按post_date排序:由于每行在结果中包含TEXT字段,因此MySQL将使用文件系统临时表进行排序。如果ID和日期一起增加,则按wp_posts.ID排序可能更好。