0

设置

我正在创建一个事件列表,用户可以在其中通过多个过滤器缩小结果范围。我没有为每个过滤器创建一个表(即 event_category、event_price),而是使用以下数据库结构(以便以后轻松/灵活地添加更多过滤器):

事件

event_id    title    description   [etc...]
-------------------------------------------

过滤器

filter_id    name        slug
-----------------------------
1            Category    category
2            Price       price

过滤器项目

filter_item_id    filter_id   name          slug
------------------------------------------------
1                 1           Music         music
2                 1           Restaurant    restaurant
3                 2           High          high
4                 2           Low           low

event_filter_item

event_id    filter_item_id
--------------------------
1           1
1           4
2           1
2           3

目标

我想查询数据库并应用用户指定的过滤器。例如,如果用户在“音乐”(类别)中搜索定价为“低”(价格)的事件,则只会显示一个事件(event_id = 1)。

URL 类似于:

www.site.com/events?category=music&price=low

所以我需要使用从 URL 收到的过滤器“slugs”查询数据库。

这是我为使其工作而编写的查询:

SELECT ev.* FROM event ev  
WHERE  
EXISTS (SELECT * FROM event_filter_item efi 
    JOIN filter_item fi on fi.filter_item_id = efi.filter_item_id
    JOIN filter f on f.filter_id = fi.filter_id 
    WHERE efi.event_id = ev.event_id AND f.slug = 'category' AND fi.slug ='music')
AND EXISTS (SELECT * FROM event_filter_item efi 
    JOIN filter_item fi on fi.filter_item_id = efi.filter_item_id
    JOIN filter f on f.filter_id = fi.filter_id 
    WHERE efi.event_id = ev.event_id AND f.slug = 'price' AND fi.slug = 'low')

此查询当前是硬编码的,但将根据 URL 中存在的过滤器和 slug 在 PHP 中动态生成。

还有一个大问题……

这是解决这个问题的合理方法吗?有没有人看到多个 EXISTS() 带有子查询以及执行多个连接的子查询的问题?这个查询非常快,数据库中只有几条记录,但是当有数千或数万条记录时呢?

非常感谢任何指导!

最好的,

克里斯

4

1 回答 1

0

虽然 EXISTS 只是 JOIN 的一种形式,但 MySQL 查询优化器对于优化执行它是出了名的“愚蠢” 。在您的情况下,它可能会对外部表进行全表扫描,然后为每一行执行相关的子查询,这势必会严重扩展。出于这个原因,人们经常将 EXISTS 重写为显式 JOIN。或者,只需使用更智能的 DBMS。

除此之外,考虑使用复合 PK filter_item,其中 FK 处于领先地位 - InnoDB 表是集群的,您希望将属于同一过滤器的项目分组在物理上靠近在一起。

顺便说一句,数万并不是“大”行数——要真正测试可伸缩性,使用数千万或更多。

于 2013-01-14T22:45:04.567 回答