代码之家  ›  专栏  ›  技术社区  ›  kovshenin

优化SQL语句

  •  1
  • kovshenin  · 技术社区  · 15 年前

    嘿,我在运行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专家,但我认为应该有办法,因为这太疯狂了;)

    谢谢!

    更新 以下是Explain返回的内容: http://twitpic.com/1cd36p

    4 回复  |  直到 14 年前
        1
  •  1
  •   Unreason    15 年前

    php通过自己的协议连接到mysql。所允许的sql的大小增加了mbs,而且由于php/mysql通信是在本地主机(或局域网)上进行的,因此它不会成为瓶颈。因此,就php和mysql之间的通信而言,sql的大小并不重要。

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

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

    此外,您只从wp_post表中选择列,但要加入更多的表-请考虑使用where exists条件重写它。

    至于优化-一定要在你的数据库中以数量级获得一些样本数据,以模拟你最终想要拥有的数据库的硬件和大小。优化查询是开发过程中不应该忘记的事情,但是过早地花费太多时间可能是不合理的。

        2
  •  2
  •   Tom H zenazn    14 年前

    你不能乐观。你需要所有的连接,因为它们是独立的过滤器,可能是因为和逻辑,也就是说,你想要海滩前面和街道外的停车场。

    你最好的办法是确保你的桌子没有碎片。在元值、元键和post-id上有一个索引。

        3
  •  1
  •   bobflux    15 年前

    这是实现基于属性的搜索的一种特别低效的方法。不幸的是,我不知道wordpress是否可以用其他方法来实现,即:每个属性都应该有自己的列和索引。这是不太灵活,但要快得多。

        4
  •  1
  •   newtover    15 年前

    正如simon sabin已经说过的那样,不能去掉连接,因为它们充当过滤器。

    为了便于阅读,最好在wp_postreta as上有一个索引(post_id,meta_key,metavalue(255))。这个顺序很重要,因为按照这个顺序计算联接中的条件,但是索引将使数据库的大小增加一倍,并减慢插入和更新的速度。

    应用乘积集的条件的顺序也不是最优的:方程应该先满足like和range条件,否则不使用索引进行过滤。

    最后但并非最不重要的杀手是按post_date排序:由于每行结果中都包含文本字段,mysql将使用文件系统临时表进行排序。如果id和日期一起增加,那么按wp_posts.id排序可能是一个更好的主意。