进行有效的横向连接(或替代)

问题描述 投票:0回答:1

上下文

我正在使用PostgreSQL的lateral联接,特别是要对一个按/限制的组执行联接。

当我查找单个记录时,该查询工作得很好,但是当我们查询多个记录时,性能会很快下降。考虑到我们有多个子查询运行单独的聚集,过滤器聚合,排序,这是有道理的。问题是,我们应该考虑哪种Postgres策略,或者如何重构以下查询以使其大规模执行?

查询

我们有三个主表,两个主表之间有一个连接表:

|经理| >-|商店| >-| Store_Products | -

我们具有给定商店记录的所有历史经理,并且我们具有商店产品的完整目录(产品可能由多个商店携带)。

目标:给出了商店ID,查询最新经理和最新销售的产品。

这是从商店到经理再到产品的内部连接。经理和产品必须按日期降序排序,并且限制为1(至少我认为这是获取最新日期的方式)。

SELECT 
    store.id as store_id,
    manager.id as manager_id,
    *
FROM 
    Stores as store,
    LATERAL (
        SELECT 
            * 
        FROM 
            Products as product 
        INNER JOIN Stores_Products store_product on store_product.product_id = product.id
        WHERE 
            store_product.store_id = store.id
        ORDER BY 
            store.date desc
        LIMIT 1
    ) p,
    LATERAL (
        SELECT 
            * 
        FROM 
            Managers as manager
        WHERE 
            manager.store_id = store.id 
        ORDER BY
            manager.date desc
        LIMIT 1
        ) m
WHERE store.name = 'ABC retail'

当您查询单个商店时,这非常理想。但是,如果您尝试批量查询(例如WHERE store.name in [...]),查询将变得非常慢,并且内存消耗也会非常快。

问题

是否有更好的方法来查询可扩展的数据?

谢谢!

注意:商店/产品给出的示例只是一个传达问题的设备。实际的架构有所不同-因此,我请不要过多考虑这是否是标准化架构的最佳方法!谢谢🙏!

sql postgresql query-performance lateral
1个回答
0
投票

也许窗口功能将运行得更快。在下面的代码中,产品订购属性保留为...,因为在您的代码段中,它们似乎是按store.date订购的,这看起来是错误的(这是商店的属性,而不是产品的属性,而不是商品的属性。商店)。

SELECT * FROM 
-- Let's rank managers within each store, giving rank=1 to the most recent
(
  SELECT id, 
         store_id, 
         RANK() OVER (PARTITION BY store_id ORDER BY date DESC) AS mgr_rank
  FROM Manager
) AS MgrRank 

JOIN

-- Let's rank products within each store, giving rank=1 to the most recent
(
  SELECT store_id,
         Products.*
         RANK() OVER (PARTITION BY store_id ORDER BY .... DESC) AS product_rank
  FROM Stores_Products JOIN Products ON product_id = Products.id
) AS ProductRank
USING(store_id) 

-- Now let's join stores themselves
JOIN Stores ON store_id = Stores.id

-- Select most recent manager and product
WHERE mgr_rank=1 AND product_rank=1 AND Stores.name='ABC retail'

请注意,没有经理或产品,此特定查询将不会输出商店。您还需要使用外部联接来包括它们。

© www.soinside.com 2019 - 2024. All rights reserved.