Dav*_*vid 10 postgresql performance index paging postgresql-10 query-performance
使用PostgreSQL 10.5。我正在尝试创建一个分页系统,用户可以在其中来回切换各种结果。
为了不使用OFFSET,我id在名为p(prevId)的参数中从上一页的最后一行传递了。然后我选择id高于p参数中传递的数字的前三行。(如本文所述)
例如,如果id上一页的最后一行是 5,我会选择前 3 行的 anid大于 5:
SELECT
id,
firstname,
lastname
FROM
people
WHERE
firstname = 'John'
AND id > 5
ORDER BY
ID ASC
LIMIT
3;
Run Code Online (Sandbox Code Playgroud)
这很好用,而且时机也不错:
Limit (cost=0.00..3.37 rows=3 width=17) (actual time=0.046..0.117 rows=3 loops=1)
-> Seq Scan on people (cost=0.00..4494.15 rows=4000 width=17) (actual time=0.044..0.114 rows=3 loops=1)
Filter: ((id > 5) AND (firstname = 'John'::text))
Rows Removed by Filter: 384
Planning time: 0.148 ms
Execution time: 0.147 ms
Run Code Online (Sandbox Code Playgroud)
虽然,另一方面,如果用户想返回上一页,事情看起来有点不同:
首先,我会传递id第一行的 ,然后在它前面加上减号以指示我应该选择id小于(正)p参数的行。即,如果id第一行的 为 6,则p参数将为-6。同样,我的查询如下所示:
SELECT
*
FROM
(
SELECT
id,
firstname,
lastname
FROM
people
WHERE
firstname = 'John'
AND id < 6
ORDER BY
id DESC
LIMIT
3
) as d
ORDER BY
id ASC;
Run Code Online (Sandbox Code Playgroud)
在上面的查询中,我首先选择id小于 6的最后 3 行,然后反转它们,以便以与开头描述的第一个查询相同的方式呈现它们。
这可以正常工作,但是由于数据库几乎遍历了我所有的行,因此性能受到影响:
Sort (cost=4252.75..4252.76 rows=1 width=17) (actual time=194.464..194.464 rows=0 loops=1)
Sort Key: people.id
Sort Method: quicksort Memory: 25kB
-> Limit (cost=4252.73..4252.73 rows=1 width=17) (actual time=194.460..194.460 rows=0 loops=1)
-> Sort (cost=4252.73..4252.73 rows=1 width=17) (actual time=194.459..194.459 rows=0 loops=1)
Sort Key: people.id DESC
Sort Method: quicksort Memory: 25kB
-> Gather (cost=1000.00..4252.72 rows=1 width=17) (actual time=194.448..212.010 rows=0 loops=1)
Workers Planned: 1
Workers Launched: 1
-> Parallel Seq Scan on people (cost=0.00..3252.62 rows=1 width=17) (actual time=18.132..18.132 rows=0 loops=2)
Filter: ((id < 13) AND (firstname = 'John'::text))
Rows Removed by Filter: 100505
Planning time: 0.116 ms
Execution time: 212.057 ms
Run Code Online (Sandbox Code Playgroud)
话虽如此,我很感激您花时间阅读到这里,我的问题是,如何使分页更有效率?
Erw*_*ter 11
性能的关键是匹配以下形式的多列索引:
CREATE UNIQUE INDEX ON people (firstname, id);
Run Code Online (Sandbox Code Playgroud)
UNIQUE,因为没有它,排序顺序可能不明确,并且您可以从对等方获得任意结果。
A UNIQUEorPRIMARY KEY约束也起作用。
虽然像您的示例中那样检查第一列是否相等(或按与查询相同的方向排序),但此索引适用于向上和向下分页,尽管它更适合向上分页。
索引就位后(并在ANALYZE表上运行后),您将不会再看到顺序扫描(除非您的表很小)。数据库不再“遍历几乎所有行”。
阅读您链接到的Markus Winand的精美演示文稿。
如果您想要跨多个分页firstname,请使用 ROW 值。向下翻页示例:
SELECT *
FROM (
SELECT id, firstname, lastname
FROM people
WHERE (firstname, id) < ('John', 6) -- ROW values
ORDER BY firstname DESC, id DESC
LIMIT 3
) d
ORDER BY firstname, id;
Run Code Online (Sandbox Code Playgroud)
有关的:
如果该SELECT列表只增加了lastname像你的榜样,你可能会尝试该列添加到索引中得到仅索引扫描的吧:
CREATE UNIQUE INDEX ON people (firstname, id, lastname);
Run Code Online (Sandbox Code Playgroud)
按此顺序索引表达式。
即将推出的Postgres 11允许对INCLUDE列进行索引,这导致索引大小更小,性能更好,适用于更多情况。喜欢:
CREATE UNIQUE INDEX ON people (firstname, id) INCLUDE (lastname);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12430 次 |
| 最近记录: |