2013-01-14 114 views
0

设置

我正在创建一个活动列表,其中用户可以通过多个过滤器缩小结果范围。而不是具有表中的每个滤波器(即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)。

的URL看起来像:

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

所以我需要与过滤“鼻涕虫”我从URL接收查询数据库。

这是我写的,使这项工作查询:

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中PHP动态生成。

还有一个大问题...

这是一个合理的方式去做这件事吗?有没有人看到有多个EXISTS()与子查询和这些子查询执行多个连接的问题?这个查询非常快,只有数据库中的几条记录,但是当数以千计或数以万计的时候呢?

任何指导真的很感激!

最佳,

克里斯

回答

0

虽然EXISTS只是一种连接形式,MySQL查询优化器是出了名的"stupid"关于最佳执行它。就你而言,它可能会对外表执行全表扫描,然后对每行执行相关子查询,这必然会严重缩小。出于这个原因,人们经常将EXISTS重写为明确的JOIN。或者,只需使用更智能的DBMS。

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

顺便说一句,成千上万的行数不是“大” - 要真正测试数千万甚至更多的可伸缩性。

+0

感谢您的信息。我不知道mysql是否愚蠢...(这两个版本是相同的,正如你可能知道的)BTW:Innodb是否对此表示赞同? – wildplasser

+0

@wildplasser我不相信。 –