基于复合表中相关记录的查询选择效率

时间:2013-01-14 16:14:59

标签: mysql sql database database-design

设置

我正在创建一个事件列表,用户可以通过多个过滤器缩小搜索范围。我没有为每个过滤器(即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()的问题,以及那些执行多个连接的子查询?这个查询非常快,数据库中只有几条记录,但是当数千或数万时呢?

非常感谢任何指导!

最佳,

克里斯

1 个答案:

答案 0 :(得分:0)

虽然EXISTS只是JOIN的一种形式,但MySQL查询优化器却以最佳方式执行"stupid"。在您的情况下,它可能会在外部表上执行全表扫描,然后为每一行执行相关子查询,这必然会严重缩放。出于这个原因,人们经常将EXISTS重写为显式JOIN。或者,只需使用更智能的DBMS。

除此之外,考虑使用filter_item的复合PK,其中FK处于前沿 - InnoDB tables are clustered,并且您希望将属于同一过滤器的项目物理地靠近在一起。

BTW,成千上万的行不是“大”行 - 要真正测试可扩展性使用数千万甚至更多。