优化多个左连接表以在多个列上进行全文搜索,具有分页的偏移量、限制和计数

问题描述

我目前有四个表需要使用左连接进行连接。 大约有 400_000(40 万)条数据记录(未来还会增长)。

除了左连接之外,还必须能够高效执行以下内容

  • 使用列采购.mandant_id、采购.公司代码、采购_mandant_names.name、公司代码.名称、采购.sequence_number、采购.年、采购.月进行全文搜索
  • 全文搜索还必须使用部分单词并忽略大小写。
  • 找到了一些值(用于计算有多少页)。
  • 还有一个偏移量、限制(或替代方法,其工作原理基本相同)来为每次搜索指定一个固定的页码(没有游标功能,我们不知道最后找到的 ID 是什么)。
  • 我们也不知道下一个页码是否是下一个更高的数字。基本上,可以立即提供更多页数。

我自己有几个想法来优化这个需求。

全文搜索

  • 一个单独的表,其中全文搜索的列连接在一个文本字段 (p.client_id::text || ' '::text || pmn.name::text) 中,另外还包含用于购买的 id 和 gin 索引 (gin_trgm_ops)
  • 一个完全不同的数据库系统,比如用于全文搜索的 sonic 或 elasticsearch,但我不知道如何最好地同步数据并在程序中查询
  • 我发现了一些类似 zombodb 的东西。 不幸的是,它的缺点是删除的记录不会从 elasticsearch 中删除。 而且 zombodb 仅适用于 linux 服务器,我更喜欢并使用 windows。

偏移、限制:

  • 搜索限制为purchase.id(从左连接中选择purchase.id)并获取这些id之后的所有数据(如果这确实导致优化不确定)
  • 添加一个始终包含当前行号和索引的列,然后在删除时也必须完全重建。不幸的是,它在一般情况下并没有真正的帮助,因为对这些数据进行过滤后,行号当然不再领先。
  • 这同样适用于 id,但删除时也可能在 id 中出现间隙。

计数

  • 目前我想不出任何优化,因为整个数据集总是要经过过滤。当前唯一的选择是使用 id 搜索仅返回 id 并对其进行计数。 然后,这些 ID 可用于提取所需的其余数据。

可以添加列或表来提供帮助。 只要保留所有数据,也可以更改结构。

如果 postgres 没有所需的功能,也可以更改数据库系统。

  • 关系
  • 开源
  • 可与 PHP 和 nodejs 连接

表格:

CREATE TABLE company_codes (
    id int2 NOT NULL,name varchar(20) NOT NULL,CONSTRAINT company_codes_pk PRIMARY KEY (id)
);

CREATE TABLE purchasing_mandant_names (
    id int2 NOT NULL,"name" varchar(50) NOT NULL,CONSTRAINT archiving_coding_keys_pkey PRIMARY KEY (id),CONSTRAINT purchasing_mandant_names_un UNIQUE (name)
);

CREATE TABLE purchasing (
    id int4 NOT NULL GENERATED BY DEFAULT AS IDENTITY,mandant_id int2 NOT NULL,company_code int4 NOT NULL,sequence_number int8 NOT NULL,"year" int2 NOT NULL,"month" int2 NOT NULL,CONSTRAINT purchasing_check_month CHECK (((month >= 1) AND (month <= 12))),CONSTRAINT purchasing_check_year CHECK (((year >= 2000) AND (year <= 2100))),CONSTRAINT purchasing_client_plant_sequence_number_key UNIQUE (mandant_id,company_code,sequence_number),CONSTRAINT purchasing_pkey PRIMARY KEY (id)
);

ALTER TABLE purchasing ADD CONSTRAINT purchasing_company_code_fk FOREIGN KEY (company_code) REFERENCES company_codes(id);
ALTER TABLE purchasing ADD CONSTRAINT purchasing_mandant_id_fkey FOREIGN KEY (mandant_id) REFERENCES purchasing_mandant_names(id) NOT VALID;

CREATE TABLE purchasing_pages (
    purchasing_id int8 NOT NULL,page_path varchar(255) NOT NULL,CONSTRAINT purchasing_pages_check_page_path CHECK (((page_path)::text ~ '^([a-zA-Z0-9\-_ ]+\/)+[a-zA-Z0-9\-_ ~]+\.[tT][iI][fF]'::text)),CONSTRAINT purchasing_pages_purchasing_id_page_path_key UNIQUE (purchasing_id,page_path)
);
ALTER TABLE purchasing_pages ADD CONSTRAINT purchasing_pages_id_fkey FOREIGN KEY (purchasing_id) REFERENCES purchasing(id) ON UPDATE CASCADE ON DELETE RESTRICT;

当前慢搜索

SELECT p.id,p.mandant_id AS mandant_code,pmn.name AS mandant_name,p.company_code,cc.name AS company_name,p.sequence_number,p.year,p.month,pp.page_path
   FROM purchasing p
     LEFT JOIN purchasing_pages pp ON p.id = pp.purchasing_id
     LEFT JOIN purchasing_mandant_names pmn ON p.mandant_id = pmn.id
     LEFT JOIN company_codes cc ON p.company_code = cc.id
       where p.mandant_id::text like '%32%'
        or pmn.name::text like '%32%'
        or p.company_code::text like '%32%'
        or cc.name::text like '%32%'
        or p.sequence_number::text like '%32%'
        or p.year::text like '%32%'
        or p.month::text like '%32%'
     order by p.id desc
     offset 10 fetch first 10 rows only

er diagramm

解决方法

我的解决方案: (我认为会有更好的选择,但这些是我自己找到的唯一选择)

全文搜索:

我为每一列创建了一个 gin_trgm_ops。 我也对狂野速度感兴趣。不幸的是,此扩展不再受支持。 Wildspeed 还具有使用较小长度 < 3 的优势。 也许以后我会再往这个方向看,看看有没有类似的扩展。

偏移、限制:

不幸的是,应用过滤器时没有优化选项。 为了优化性能,我在应用程序本身中内置了几个选项。 如果您获得指向页面的直接链接,则必须使用偏移量、限制,因为没有其他可能性。 除了这种可能性,现在还有一个偏移量 - 前一个偏移量和最后一个 id。这样,索引至少会用于进一步导航。 但是对于直接跳转,没有 optimnierungsmöglichkeiten,因为数据也被过滤了。

计数

我直接使用了count(*) OVER() 和offset limit 搜索过滤器结合使用,所以只需要执行一个查询。这是我为此找到的唯一优化。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...