如何改进慢速自定义查询? (带有自定义字段的子查询+内部联接)

时间:2014-07-08 00:14:00

标签: php mysql sql wordpress advanced-custom-fields

我有一个查询,用于返回预订系统的可用房间

使用Advanced Custom Fields,我有一个自定义帖子类型,表示具有各种字段的预订

此处的计划是找到所有已预订的子查询房间,然后通过选择不在子查询返回的结果集中的帖子来获取所有可用房间

我的预订自定义帖子有一个“terrain_id”,应该匹配房间的post id(露营或别墅)

第一个内部联接用于房间ID(terrain_id),第二个内部联接用于开始日期,最后一个用于结束日期

所以基本上我将room_id与post_id匹配,并在指定的时间间隔内返回所有不可用的房间,然后我得到子查询结果中不存在的所有IDS以获取我的可用房间

问题如下:

此查询在一个微小的数据样本(大约2000个预订,100个房间)上运行大约5-6秒

我尝试了不同的方法来优化它,但我几乎被卡住了

所有相关领域都有索引

子查询本身运行大约0.030秒,所以我不认为内连接是这里的问题,大部分问题似乎都在SELECT中,而不是EXISTS

使用默认的wordpress方法并且循环不是选项,因为无法执行所需的操作,我需要为每个记录单独查询所有自定义字段

如何提高查询效果?

如何选择大约100条记录数组中不存在的基本属性可能需要这么长时间?

SELECT wps.ID, wps.post_title, wps.post_type, wps.post_status
FROM wp_posts wps, wp_postmeta wpm
WHERE NOT EXISTS
(
    SELECT
      p.ID,
      pm_ti.meta_value as tiv,
      pm_ti.meta_key as tik,
      pm_ed.meta_key as edk,
      pm_ed.meta_value as edv,
      pm_sd.meta_key as sdk,
      pm_sd.meta_value as sdv
    FROM
      wp_posts p
    INNER JOIN wp_postmeta pm_ti ON (pm_ti.post_id = p.ID )
    INNER JOIN wp_postmeta pm_ed ON (pm_ed.post_id = p.ID )
    INNER JOIN wp_postmeta pm_sd ON (pm_sd.post_id = p.ID )
    WHERE NOT (pm_ed.meta_value <= '{$start}' OR pm_sd.meta_value >= '{$end}')
    AND pm_ti.meta_key='terrain_id' and p.post_status='publish' and wps.ID = pm_ti.meta_value and pm_ed.meta_key='e_date' and pm_sd.meta_key='s_date'
    GROUP BY p.ID
)
AND wpm.post_id = wps.ID AND wps.post_status='publish' AND wps.ID = icl_translations.element_id
and (wps.post_type='camping' or wps.post_type='cottages') GROUP BY wps.ID
");

解释结果:

2 个答案:

答案 0 :(得分:2)

我不能很好地了解你的数据100%,但这里的想法是一样的。而不是使用相关的子查询尝试这样的事情。

SELECT wps.ID, wps.post_title, wps.post_type, wps.post_status
FROM wp_posts wps, wp_postmeta wpm
WHERE wpm.post_id NOT IN
(
    SELECT
      DISTINCT pm_ti.meta_value
    FROM
      wp_posts p
    INNER JOIN wp_postmeta pm_ti ON (pm_ti.post_id = p.ID )
    INNER JOIN wp_postmeta pm_ed ON (pm_ed.post_id = p.ID )
    INNER JOIN wp_postmeta pm_sd ON (pm_sd.post_id = p.ID )
    WHERE NOT (pm_ed.meta_value <= '{$start}' OR pm_sd.meta_value >= '{$end}')
    AND pm_ti.meta_key='terrain_id'
    AND p.post_status='publish'
    AND pm_ed.meta_key='e_date'
    AND pm_sd.meta_key='s_date'
)
AND wpm.post_id = wps.ID
AND wps.post_status='publish'
AND wps.ID = icl_translations.element_id
AND (wps.post_type='camping' or wps.post_type='cottages')

我们的想法是在一个未链接到主要选择的选择中返回您不想要的ID列表。然后使用NOT IN过滤主选择。

只是尝试一下 - 没有经过测试。

答案 1 :(得分:0)

我终于找到了一个不错的答案

问题的根源是这样的嵌套查询本身就很慢,所以我用负LEFT OUTER JOIN替换了WHERE ... NOT IN

我开始优化内部查询,因为它很草率,可以用更简单的方式实现相同的结果

然后,通过用LEFT OUTER JOIN替换WHERE条件来获得相同的结果

这个问题非常有用:

SQL Nested Query slow using IN

原始查询需要5到15秒,

修改后的查询运行时间少于0.05秒

SELECT wps.ID, wps.post_title, pm_ti.meta_value

FROM wp_posts wps

LEFT OUTER JOIN 
(

   SELECT
   pm_ti.meta_value
   FROM
   wp_postmeta pm_ti
   INNER JOIN wp_postmeta pm_ed ON (pm_ed.post_id = pm_ti.post_id )
   INNER JOIN wp_postmeta pm_sd ON (pm_sd.post_id = pm_ti.post_id )
   WHERE NOT (pm_ed.meta_value <= '2014-07-01' OR pm_sd.meta_value >= '2014-07-12')
   AND pm_ti.meta_key='terrain_id' AND pm_ed.meta_key='e_date' AND pm_sd.meta_key='s_date'

) pm_ti

ON wps.ID = pm_ti.meta_value

INNER JOIN wp_icl_translations icl ON (icl.element_id = wps.ID)

WHERE pm_ti.meta_value IS null AND wps.post_status='publish' 

AND (wps.post_type='camping' OR wps.post_type='cottages')  AND icl.language_code = 'fr'

GROUP BY wps.ID