postgresql 优化查询以获取另一个表中具有最高筛选计数的行

xqkwcwgp  于 2023-01-05  发布在  PostgreSQL
关注(0)|答案(2)|浏览(153)

我试图创建一个最优的查询,让数据库返回经常借阅科幻小说的读者的名字,这就是我要优化的:

SELECT reader.name, 
COUNT (CASE WHEN book.status_id = 1 AND book.category_id = 2 THEN 1 END)
FROM reader
JOIN book ON book.reader_id = reader.id
GROUP BY reader.name
ORDER BY COUNT (CASE WHEN book.status_id = 1 AND book.category_id = 2 THEN 1 END) DESC
LIMIT 10;

除了INNER JOIN或内存消耗增加之外,我如何改进查询?
这是我的ERD图:

mqxuamgl

mqxuamgl1#

你可以试着在你的连接语句中添加你的条件,并且只使用总数,这实际上取决于你有多少数据等等。

SELECT reader.name, 
COUNT(1) AS COUNTER
FROM reader
JOIN book ON book.reader_id = reader.id
AND book.status_id = 1
AND book.category = 2
GROUP BY reader.name
ORDER BY COUNTER DESC
LIMIT 10;
vuv7lop3

vuv7lop32#

假设至少有10个读取器通过了标准(就像另一个答案也默默地假设),否则您得到的结果行少于10行。
从过滤器开始。在连接到第二个表之前 * 聚合&限制。更便宜:

SELECT r.reader_id, r.surname, r.name, b.ct
FROM  (
   SELECT reader_id, count(*) AS ct
   FROM   book
   WHERE  status_id = 1
   AND    category_id = 2
   GROUP  BY reader_id
   ORDER  BY ct DESC, reader_id  -- tiebreaker
   LIMIT  10
   ) b
JOIN   reader r ON r.id = b.reader_id
ORDER  BY b.ct DESC, r.reader_id;  -- tiebreaker

(status_id, category_id)上建立一个多列索引会有很大的帮助。或者,如果两个 predicate 中的任何一个是非常有选择性的,那么在两列中的一列上建立一个索引。如果这个特定查询的性能是您的首要目标,那么使用这个partial多列索引:

CREATE INDEX book_reader_special_idx ON book (reader_id)
WHERE status_id = 1 AND category_id = 2;

通常,您会改变查询,那么最后一个索引就太专业化了。
补充要点:

  • reader_id分组,reader_id是主键(我假设)并保证是唯一的-与reader.name相反!您的原始文件可能会完全失败,因为从ERD的外观来看,name只是"名"。

integer分组通常比用varchar(25)分组快得多(两次),但这是次要的,正确性是第一位的。

  • 还可以输出surnamereader_id来消除相同名称的歧义(即使名称和姓氏也不一定是唯一的)。
  • count(*)count(1)快,但执行的操作完全相同。
  • ORDER BY子句中添加一个tiebreaker,以获得稳定的排序顺序和确定性结果。(否则,每次计数相同时,结果都可能不同。)

相关问题