下面是我尝试运行的代码的精简版本:
CREATE OR REPLACE VIEW Union_Test AS
(
SELECT
C.Id
, C.Code
, C.Name
, S.Id AS Status_Id
FROM
Client C
INNER JOIN
Status S ON S.Id = 1
UNION ALL
SELECT
CA.Id
, CA.Code
, CA.Name
, S.Id AS Status_Id
FROM
Client_Archive CA
INNER JOIN
Status S ON S.Id = 2
);
与软删除和1个表(客户机)不同,当客户机被删除时,该客户机被移动到客户机存档表中。上面的视图用于恢复整个客户机集。我希望保持表相对干净,因此将status\u id添加到视图中,而不是表中。
然后执行以下代码。这并不是我所要做的,因为我实际上是根据页面大小变量返回页码的,但是下面的代码可以解决这个问题。
SELECT
Id
, ROW_NUMBER() OVER (ORDER BY Code) AS Rownum
FROM
Union_Test
client(1000000行)和client_archive(1行)表在id(pk)、code和name上有btree索引status表在id(pk)和code上有btree索引。这些是作为健全性检查添加的,因为状态表只有5行。
上述查询生成以下计划:
|QUERY PLAN |
|----------------------------------------------------------------------------------------------------|
|WindowAgg (cost=165869.97..183369.97 rows=1000000 width=45) (actual time=8908.954..9490.758 rows=10|
| -> Sort (cost=165869.97..168369.97 rows=1000000 width=37) (actual time=8908.933..9062.302 rows=1|
| Sort Key: "*SELECT* 1".code |
| Sort Method: quicksort Memory: 102702kB |
| -> Result (cost=0.00..66212.13 rows=1000000 width=37) (actual time=0.027..604.587 rows=100|
| -> Append (cost=0.00..56212.12 rows=1000000 width=37) (actual time=0.027..495.570 ro|
| -> Subquery Scan on "*SELECT* 1" (cost=0.00..51210.03 rows=999999 width=37) (a|
| -> Nested Loop (cost=0.00..41210.04 rows=999999 width=159) (actual time=|
| -> Seq Scan on status s (cost=0.00..1.06 rows=1 width=0) (actual t|
| Filter: (id = 1) |
| Rows Removed by Filter: 4 |
| -> Seq Scan on client c (cost=0.00..31208.99 rows=999999 width=37)|
| -> Subquery Scan on "*SELECT* 2" (cost=0.00..2.09 rows=1 width=37) (actual tim|
| -> Nested Loop (cost=0.00..2.08 rows=1 width=159) (actual time=0.033..0.|
| -> Seq Scan on client_archive ca (cost=0.00..1.01 rows=1 width=37)|
| -> Seq Scan on status s_1 (cost=0.00..1.06 rows=1 width=0) (actual|
| Filter: (id = 2) |
| Rows Removed by Filter: 4 |
|Planning Time: 0.299 ms |
|Execution Time: 9553.810 ms |
查询中没有使用索引,执行起来需要将近10秒。
如果我删除查询的union all和client\u archive部分,如下所示:
CREATE OR REPLACE VIEW Union_Test AS
(
SELECT
C.Id
, C.Code
, C.Name
, S.Id AS Status_Id
FROM
Client C
INNER JOIN
Status S ON S.Id = 1
);
当我运行上面的rownum查询时,我得到以下计划:
|QUERY PLAN |
|----------------------------------------------------------------------------------------------------|
|WindowAgg (cost=0.42..156177.45 rows=999999 width=45) (actual time=0.048..2059.087 rows=999999 loop|
| -> Nested Loop (cost=0.42..141177.46 rows=999999 width=37) (actual time=0.038..1355.683 rows=999|
| -> Index Scan using client_code_idx on client c (cost=0.42..128676.41 rows=999999 width=37|
| -> Materialize (cost=0.00..1.07 rows=1 width=0) (actual time=0.000..0.000 rows=1 loops=999|
| -> Seq Scan on status s (cost=0.00..1.06 rows=1 width=0) (actual time=0.012..0.013 r|
| Filter: (id = 1) |
| Rows Removed by Filter: 4 |
|Planning Time: 0.213 ms |
|Execution Time: 2125.573 ms |
考虑到表上的索引,这是我所期望的计划。
如果我删除与状态表的联接并恢复查询的union all和client\ U存档部分,如下所示:
CREATE OR REPLACE VIEW Union_Test AS
(
SELECT
C.Id
, C.Code
, C.Name
, 1 AS Status_Id
FROM
Client C
UNION ALL
SELECT
CA.Id
, CA.Code
, CA.Name
, 2 AS Status_Id
FROM
Client_Archive CA
);
当我运行上面的rownum查询时,我得到以下计划:
|QUERY PLAN |
|----------------------------------------------------------------------------------------------------|
|WindowAgg (cost=0.56..163684.56 rows=1000000 width=45) (actual time=0.032..2579.727 rows=1000000 lo|
| -> Result (cost=0.56..148684.56 rows=1000000 width=37) (actual time=0.023..1840.123 rows=1000000|
| -> Merge Append (cost=0.56..138684.56 rows=1000000 width=37) (actual time=0.022..1694.317 |
| Sort Key: c.code |
| -> Index Scan using client_code_idx on client c (cost=0.42..128676.41 rows=999999 wi|
| -> Index Scan using client_archive_code_idx on client_archive ca (cost=0.13..8.14 ro|
|Planning Time: 0.176 ms |
|Execution Time: 2647.764 ms |
再一次-和预期的差不多。看起来,视图中的unionall和join的组合,然后对视图的查询中的orderby,产生了一个次优的计划。或者我遗漏了一些明显的东西。我对postgresql比较陌生,所以后者可能就是这样!
一旦数据被缩减到我要查找的页面上,我就不能在以后添加状态,因为按状态排序(显然,在上面的示例中,排序是通过代码完成的)是提供给最终用户的选项之一。
我知道我可以将所有内容移动到一个客户机表中,甚至可以对状态id文本(本例中为1或2)进行排序,而无需连接到状态表-但这否定了我尝试对db设计所做的部分工作。我也不打算创建一个带有索引的物化视图,或者创建一个保存客户机和客户机存档数据的client\u all表,除非没有其他选项。
谢谢,里奇。
暂无答案!
目前还没有任何答案,快来回答吧!