大表中SQL查询的性能

问题描述 投票:0回答:1

我有一个如下所示的 postgres 表:

id: int [PK]
scenario_id: int [FK]
node_id: int Optional[FK]
element_id: int Optional[FK]
result: char(20)
value: double
unit: char(12)

我在其中保存图表的节点和元素的各种结果的行。如果结果变量假设 x 仅对节点有效,则该行如下所示:

id    scenario_id    node_id    element_id    result    value    unit
1     1              100        [null]        x         0.1      'MW'

我意识到,添加不同的场景后,这个表变得非常大(5000 个场景中的 40m 条目)非常快。根据 pgadmin,我查询获取 1 个场景的所有结果平均需要 7 秒。

如何让这张表更加高效,让查询不花7秒?


查询:

SELECT * FROM simulation.scenario_results t
    WHERE t.scenario_id = 5000

解释一下:

pgadmin

DLL 脚本:

-- Table: simulation.scenario_results

-- DROP TABLE IF EXISTS simulation.scenario_results;

CREATE TABLE IF NOT EXISTS simulation.scenario_results
(
    id integer NOT NULL DEFAULT nextval('simulation.scenario_results_id_seq'::regclass),
    scenario_id integer NOT NULL,
    node_id integer,
    element_id integer,
    result character varying(20) COLLATE pg_catalog."default" NOT NULL,
    value double precision NOT NULL,
    unit character varying(12) COLLATE pg_catalog."default",
    CONSTRAINT scenario_results_pkey PRIMARY KEY (id),
    CONSTRAINT scenario_results_element_id_fkey FOREIGN KEY (element_id)
        REFERENCES simulation.elements (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT scenario_results_node_id_fkey FOREIGN KEY (node_id)
        REFERENCES simulation.nodes (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT scenario_results_scenario_id_fkey FOREIGN KEY (scenario_id)
        REFERENCES simulation.scenarios (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
)

TABLESPACE pg_default;

ALTER TABLE IF EXISTS simulation.scenario_results
    OWNER to postgres;
sql postgresql performance datatable query-optimization
1个回答
0
投票

看起来您拥有的唯一索引是带有

unique
primary key
。即使您要过滤的列上有一个简单的默认 btree 也会加快速度:

create index on simulation.scenario_results(scenario_id);

不要忘记之后

vacuum analyze simulation.scenario_results;
,然后再次测试您的查询,看看您的
seq scan
被更快的
index scan
取代。前者意味着您的查询每次都必须阅读整个内容才能找到您的特定场景,后者意味着它现在检查可以完全跳过表的哪些部分以及在哪里找到特定的
scenario_id

您可以通过两种方式进一步加快速度:要么使索引成为覆盖索引,这意味着您可能想要从表中获得的所有数据都将位于其中,因此查询将能够直接从索引中读取所有内容,而无需必须访问桌子,这是一个

index-only scan

create index on simulation.scenario_results(scenario_id)
   include(id,node_id,element_id,result,value,unit);

或者您可以

cluster
以加快从常规轻量级索引跳转的方式排列表格:

create index idx1 on simulation.scenario_results(scenario_id);
cluster verbose simulation.scenario_results using idx1;
analyze simulation.scenario_results ;

请注意,上述三个命令中的每一个都必须在自己的单独事务中运行。

© www.soinside.com 2019 - 2024. All rights reserved.