连接查询的Postgresql分页性能

连接查询的Postgresql分页性能,postgresql,performance,query-optimization,Postgresql,Performance,Query Optimization,我有两张桌子: 产品~20mln记录 标记~3500万条记录 并对此类查询存在性能问题: SELECT products.name FROM products INNER JOIN tags ON tags.product_id=products.id WHERE products.categoryid IN (1,2,3..) AND tags.id = 3 ORDER BY products.position LIMIT 64 OFFSET 0; 当偏移量很小时,一切都很

我有两张桌子:

产品
~20mln记录

标记
~3500万条记录

并对此类查询存在性能问题:

SELECT products.name 
FROM products 
INNER JOIN tags ON tags.product_id=products.id
WHERE 
  products.categoryid IN (1,2,3..) AND
  tags.id = 3 
ORDER BY products.position 
LIMIT 64 OFFSET 0;
当偏移量很小时,一切都很好。当偏移量大于1000时,查询执行10-80秒

已具有按位置排序的
索引(产品表)和
产品id、id
(标签表)

tags.id
在查询中可以是不同的,不同的标签的结果元素也不同,所以我想我不能使用游标字段这样的方法


如何优化此查询?

您可以在加入前减少filer tags表中的数据集,如:

SELECT products.name 
FROM products 
INNER JOIN (
  SELECT id FROM tags WHERE tags.id = 3
) tags ON tags.product_id=products.id
WHERE 
  products.categoryid IN (1,2,3..)
ORDER BY products.position 
LIMIT 64 OFFSET 0;
或分别筛选两个表并联接结果:

SELECT products.name 
FROM (
  SELECT name, position FROM products WHERE products.categoryid IN (1,2,3..)
) products 
INNER JOIN (
  SELECT id FROM tags WHERE tags.id = 3
) tags ON tags.product_id=products.id
ORDER BY products.position 
LIMIT 64 OFFSET 0;

可以很好地使用键集分页。最初的查询是:

SELECT products.name, products.position, products.id
FROM products 
INNER JOIN tags ON tags.product_id=products.id
WHERE 
  products.categoryid IN (1,2,3..) AND
  tags.id = 3 
ORDER BY products.position, products.id
LIMIT 64;
下面的查询将是

SELECT products.name, products.position, products.id
FROM products 
INNER JOIN tags ON tags.product_id=products.id
WHERE 
  products.categoryid IN (1,2,3..) AND
  tags.id = 3
  AND (products.position, products.id) > ($1, $2)
ORDER BY products.position, products.id
LIMIT 64;
其中,
$1
$2
是前面的查询返回的最后一个值


products(products.position,products.id)上的索引可以快速查询。

您的统计数据看起来有点不对劲(product表中预期的
rows=1513209
与实际的
rows=17547
)。您可能希望首先在两个表上运行
分析。您可以尝试的另一件事是使
项目排序\u索引
覆盖
名称
列(请参阅)。@Marth统计信息是关闭的,因为“预期”行没有考虑限制,而实际行考虑限制。我不理解您对光标的反对意见。或者“游标字段”与游标不同?@jjanes将字段添加到表中,这将有助于计算页面位置(如)。这不是我的问题关键集分页应该可以正常工作,只要人们实际上正在逐步浏览数据,而不是想跳转到第50页而不首先看到1-49。如果位置不是唯一的,您需要通过以下方式在订单中添加一个平局断路器:加入、加入, которые объединяются по условию? 标签id=3,请用英文写下您的评论,这样用户就可以阅读和协作。关于我的建议,最好的测试方法是在数据集上进行测试。只需在这里运行查询和注释,是否有用?如果位置是布尔字段呢?或者如果我需要使用products.stock(真/假)。结果不会按升序什么
布尔值
字段排序?你的问题里没有那样的。但向结果或
orderby
子句中添加更多列是很容易的。
SELECT products.name, products.position, products.id
FROM products 
INNER JOIN tags ON tags.product_id=products.id
WHERE 
  products.categoryid IN (1,2,3..) AND
  tags.id = 3
  AND (products.position, products.id) > ($1, $2)
ORDER BY products.position, products.id
LIMIT 64;