sql - 制作有效的横向连接(或替代方法)
问题描述
语境
我正在玩 PostgreSQL 的lateral
加入,特别是在 group by/limit 上执行加入。
当我查找单个记录时,查询工作得非常好,但是当我们查询多条记录时,性能很快就会下降。这是有道理的,因为我们有多个子查询运行单独的收集、过滤聚合、排序。问题是,我们应该看什么 Postgres 策略,或者我们如何重构下面的查询以使其大规模执行?
询问
我们有三个主表,其中两个之间有一个联结表:
|经理| >- |专卖店| >- |店铺_产品| -< 产品
我们有给定商店记录的所有历史经理,我们有商店的完整产品目录(产品可能由多个商店携带)。
目标:给定一个Store ID,查询最近的Manager和最近售出的Product。
这是从 Store 到 Manager 和 Product 的内部连接。Manager & Product 必须按日期 desc 排序并限制为 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 [...]
),查询会变得非常缓慢并且会很快消耗内存。
问题
有没有更好的方法来查询可以很好扩展的数据?
谢谢!
注意:给出的商店/产品示例只是一个传达问题的设备。实际的架构是不同的 - 所以我要求不要过多考虑这是否是规范化架构的最佳方式!谢谢 !
解决方案
也许窗口函数会运行得更快。在下面的代码中留下了产品订购属性,...
因为在您的代码段中它们似乎是按 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'
请记住,此特定查询不会输出没有经理或产品的商店。您还需要使用外部连接来包含它们。
推荐阅读
- node.js - 除了全局变量之外,是否还有其他需要通用节点模块的替代方法?
- objective-c - 在 dispatch_async 队列中的 weakself(dispatch_get_main_queue(), ^{})
- python - 如何通过剪贴板仅读取从 Excel 复制到 pandas DF 的非相邻列?
- html - 如何检查视频是否支持对象拟合
- android - 如何使 CardView 居中并获得正确的颜色背景?
- python - Python import 语句只识别来自某些目录的包?
- javascript - Select2 渲染不好,样式坏了
- java - JAXB / Jackson 不允许为 HashSet 项目选择名称
- c# - 如何将列从一个数据网格复制到另一个
- apache - Perl CGI 的漂亮 URL