我正在创建一个事件列表,用户可以通过多个过滤器缩小搜索范围。我没有为每个过滤器(即event_category,event_price)提供表格,而是具有以下数据库结构(以便以后轻松/灵活地添加更多过滤器):
事件
event_id title description [etc...]
-------------------------------------------
fllter
filter_id name slug
-----------------------------
1 Category category
2 Price price
filter_item
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)。
网址如下所示:
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中存在的过滤器和slugs在PHP中动态生成。
这是一个合理的方法吗?有没有人看到有多个带有子查询的EXISTS()的问题,以及那些执行多个连接的子查询?这个查询非常快,数据库中只有几条记录,但是当数千或数万时呢?
非常感谢任何指导!
最佳,
克里斯
答案 0 :(得分:0)
虽然EXISTS只是JOIN的一种形式,但MySQL查询优化器却以最佳方式执行"stupid"。在您的情况下,它可能会在外部表上执行全表扫描,然后为每一行执行相关子查询,这必然会严重缩放。出于这个原因,人们经常将EXISTS重写为显式JOIN。或者,只需使用更智能的DBMS。
除此之外,考虑使用filter_item
的复合PK,其中FK处于前沿 - InnoDB tables are clustered,并且您希望将属于同一过滤器的项目物理地靠近在一起。