如何优化内部自我连接?

时间:2019-06-02 00:39:32

标签: postgresql search inner-join

我有100万桶球。每个球都有许多属性(并非每个球都具有所有属性,例如,高尔夫球不能充气/放气)。

buckets and balls visualization

用户根据特定的球要求寻找铲斗和球。例如,用户可能会问哪些存​​储桶包含golf ballred ballred soccer ball?在此示例中,只有一个红色足球但没有其他红色球的水桶无法满足查询要求(我们需要另一个红色球;两个红色足球可以做到)。

应用程序必须返回bucket idsball 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)需要的时间更少从我那里学习基础技术(这只是业余爱好)。

0 个答案:

没有答案