我有100万桶球。每个球都有许多属性(并非每个球都具有所有属性,例如,高尔夫球不能充气/放气)。
用户根据特定的球要求寻找铲斗和球。例如,用户可能会问哪些存储桶包含golf ball
,red ball
和red soccer ball
?在此示例中,只有一个红色足球但没有其他红色球的水桶无法满足查询要求(我们需要另一个红色球;两个红色足球可以做到)。
应用程序必须返回bucket ids
和ball ids
,它们都满足每个存储桶中的要求(最好是将匹配的球ID与它所匹配的查询相关联的方式)。例如,可能的回报如下所示:
[{
bucket_id: 1,
ball_ids: [{
query: “golf ball”,
ball_id: 1,
},{
query: “red ball”,
ball_id: 6,
},{
query: “red soccer ball”,
ball_id: 14,
}]
},
... other matches ...
]
但这也会做得很好:
bucket_id: 1,
ball_ids: {
query0_ball_id: 1,
query1_ball_id: 6,
query2_ball_id: 14
}
为清楚起见,我已经尝试了许多解决此问题的方法,并已对不同的选择进行了基准测试。我之所以要问这个问题,是因为我希望有更多我不知道的解决方案或优化(我已经为表格列建立了索引,但是我愿意寻求更好的索引)。
我当前的解决方案是使用如下表:
ball_id | ball_type | color | weight | is_inflated | bucket_id
--------------------------------------------------------------
0 | cricket | red | 157 | NULL | 1
1 | golf | green | 45.93 | NULL | 1
[etc.]
查询然后依赖于自身内部联接(FROM balls as b0 INNER JOIN balls as b1
),其中b0.bucket_id = b1.bucket_id
。当我只寻找其中装有两种球的水桶时,这是相当不错的表现。当我寻找总体上很少见的多个球时,也很好。
问题是,当我搜索全部发生10,000次的三个球时,即使结果只有30个存储桶,连接也变得非常昂贵。因此,我希望在100ms以下运行的查询要花费5000ms以上的时间(显然,在查询中再添加一个普通的球将使问题倍增)。注意:(postgres)查询中最昂贵的部分似乎是“并行位图堆扫描”,其含义我尚未充分理解。
如何优化当前的解决方案?(或者我应该真的切换到针对此问题的其他东西)
我愿意接受其他数据结构,但我认为这个问题太开放了。我要坚持我的postgres db和上面描述的结构,除非出于某种原因这是一个糟糕的主意,因为:(1)从概念上讲,它使其他开发人员更容易进入此项目,(2)需要的时间更少从我那里学习基础技术(这只是业余爱好)。