修改此查询的更好方法是使子查询更具体?

时间:2014-07-31 13:20:12

标签: mysql subquery

这是我正在使用的当前查询,它到目前为止做得很好:

SELECT   a.*
FROM     ads AS a
WHERE    id = (
   SELECT   id
   FROM     ads AS b
   WHERE    a.zone_name=b.zone_name
      AND   publish_date <= CURDATE() AND expire_date >= CURDATE() AND active = 1
   LIMIT 1
)

每个现有区域返回一个广告,然后在按区域排序后,在模板中的相应位置显示相应的广告。

现在我们已经引入了响应式布局,因此区域不能始终适合广告的相同维度,我希望始终获取最适合的广告。我首先使用Javascript阅读浏览器分辨率,然后将其传回PHP,然后PHP和MySQL可以决定适合哪些广告。

但我不知道如何比我在下面提供的解决方案更容易适应查询条件,我想要一个更好的解决方案。由于不同的区域将在相同的分辨率上适应不同的尺寸,我需要一种方法来指定每个区域的大小,我能想到的唯一方法是逐个获取它们,为每个区域指定所需的大小,然后对它们进行UNION ALL

但执行起来似乎相当缓慢,我想知道是否有一个更好的可以简化条件并可能消除publish_date条件的重复,避免UNION因此(希望)执行得更快?

(SELECT ads.* FROM ads WHERE zone_name = 'b' AND width=468 AND publish_date <= CURDATE() AND expire_date >= CURDATE() AND active = 1 LIMIT 1)
UNION ALL
(SELECT ads.* FROM ads WHERE zone_name = 'a1' AND width=728 AND publish_date <= CURDATE() AND expire_date >= CURDATE() AND active = 1 LIMIT 1)

...

1 个答案:

答案 0 :(得分:1)

这是您的查询:

SELECT   a.*
FROM     ads a
WHERE    id = (SELECT   id
               FROM     ads b
               WHERE    a.zone_name=b.zone_name AND
                        publish_date <= CURDATE() AND
                        expire_date >= CURDATE() AND
                        active = 1
              LIMIT 1
             );

您似乎并不关心您获得哪些广告(例如获取最新广告)。

开始表现的好地方是一个指数:

create index idx_ads_4 on ads(zone_name, active, expire_date, publish_date)

这是一个&#34;覆盖索引&#34;,这意味着子查询中使用的所有列都使用索引。

接下来,如果区域的大小不同,则将其放入表中并使用join。完整查询类似于:

select a.*
from (select 'b' as zone_name, 468 as width union all
      select 'a1', 728
     ) ZoneWidths join
     ads a
     on a.zone_name = zonewidths.zone_name and a.width = zonewidths.width
where id = (SELECT   id
            FROM     ads b
            WHERE    a.zone_name=b.zone_name AND
                     a.width = b.width AND
                     publish_date <= CURDATE() AND
                     expire_date >= CURDATE() AND
                     active = 1
            LIMIT 1
           );

此查询的相应索引还需要width

create index idx_ads_5 on ads(zone_name, width, active, expire_date, publish_date)