使用“OR”连接单个表中的两列太慢

大灾变

我正在尝试从上个月的最后一天到当月的最后一天(时间为 '15:00:00')获取总交易计数和金额

表结构

CREATE TABLE mjr_agent
(
    id bigint NOT NULL UNIQUE,
    head_agent_id varchar(20),
    code varchar(20) NOT NULL UNIQUE,
    password varchar(200) NOT NULL,
    agent_type smallint NOT NULL,
    agent_group smallint NOT NULL,
    division varchar(100) NOT NULL,
    township varchar(200) NOT NULL,
    shop_name varchar(200),
    contact_name varchar(150) NOT NULL,
    ph_no varchar(50),
    contact_ph_no varchar(50),
    address varchar(500),
    record_reg_id bigint NOT NULL,
    record_upd_id bigint NOT NULL,
    record_reg_date timestamp DEFAULT current_timestamp NOT NULL,
    record_upd_date timestamp DEFAULT current_timestamp NOT NULL,
    user_id bigint,
    PRIMARY KEY (id)
) WITHOUT OIDS;

CREATE TABLE mjr_transaction_item
(
    id bigint NOT NULL UNIQUE,
    exl_id bigint NOT NULL,
    sr_no int NOT NULL,
    txn_id varchar(20) NOT NULL,
    txn_date timestamp NOT NULL,
    txn_status smallint NOT NULL,
    src_id varchar(20) NOT NULL,
    src_type smallint NOT NULL,
    src_name varchar(100),
    src_ocpt varchar(100),
    dest_id varchar(20) NOT NULL,
    dest_type smallint NOT NULL,
    dest_name varchar(100),
    desc_ocpt varchar(100),
    amount numeric,
    reason varchar(250),
    medium smallint NOT NULL,
    record_reg_id bigint NOT NULL,
    record_upd_id bigint NOT NULL,
    record_reg_date timestamp DEFAULT current_timestamp NOT NULL,
    record_upd_date timestamp DEFAULT current_timestamp NOT NULL,
    PRIMARY KEY (id)
) WITHOUT OIDS;

每个表中的总记录数

mjr_agent = 700 和 mjr_transaction_item = 1136043

询问

SELECT
    agnt.ID AS agent_id,
    COUNT ( DISTINCT txi.ID ) AS total_transaction,
    SUM ( txi.amount ) AS total_amount
FROM
    mjr_agent agnt
    LEFT JOIN mjr_transaction_item txi ON agnt.code = txi.src_id 
    OR agnt.code = txi.dest_id
WHERE
    CONCAT (( date_trunc( 'month', to_timestamp( '2019-04-01', 'YYYY-MM-DD' )) + INTERVAL '1 month' - INTERVAL '1 day' ) :: DATE, ' 15:00:00' ) :: TIMESTAMP >= txi.txn_date 
    AND txi.txn_date >= CONCAT (( date_trunc( 'month', to_timestamp( '2019-04-01', 'YYYY-MM-DD' )) :: DATE - 1 ), ' 15:00:00' ) :: TIMESTAMP 
GROUP BY
    agnt.ID 

查询计划

GroupAggregate  (cost=1000.27..52530.69 rows=86 width=48) (actual time=779.221..14716.528 rows=400 loops=1)
  Group Key: agnt.id
  Buffers: shared hit=10729
  ->  Nested Loop  (cost=1000.27..52523.53 rows=812 width=48) (actual time=759.898..14708.292 rows=10132 loops=1)
        Join Filter: (((agnt.code)::text = (txi.src_id)::text) OR ((agnt.code)::text = (txi.dest_id)::text))
        Rows Removed by Join Filter: 65321568
        Buffers: shared hit=10729
        ->  Index Scan using mjr_agent_pkey on mjr_agent agnt  (cost=0.27..189.56 rows=86 width=66) (actual time=0.045..1.827 rows=700 loops=1)
              Buffers: shared hit=92
        ->  Materialize  (cost=1000.00..50911.10 rows=947 width=156) (actual time=0.001..5.658 rows=93331 loops=700)
              Buffers: shared hit=10637
              ->  Gather  (cost=1000.00..50906.37 rows=947 width=156) (actual time=0.809..616.836 rows=93331 loops=1)
                    Workers Planned: 4
                    Workers Launched: 4
                    Buffers: shared hit=10637
                    ->  Parallel Seq Scan on mjr_transaction_item txi  (cost=0.00..49811.67 rows=237 width=156) (actual time=0.150..625.545 rows=18666 loops=5)
                          Filter: ((txn_date >= (concat(((date_trunc('month'::text, to_timestamp('2019-04-01'::text, 'YYYY-MM-DD'::text)))::date - 1), ' 15:00:00'))::timestamp without time zone) AND ((concat((((date_trunc('month'::text, to_timestamp('2019-04-01'::text, 'YYYY-MM-DD'::text)) + '1 mon'::interval) - '1 day'::interval))::date, ' 15:00:00'))::timestamp without time zone >= txn_date))
                          Rows Removed by Filter: 208542
                          Buffers: shared hit=47351
Planning time: 0.582 ms
Execution time: 14718.609 ms

硬件规格

Cent OS 7.6,内存 32 GB,8 个 CPU,Postgres 10.0

平均查询执行时间约为12秒,这对我的应用程序来说是不可接受的。我没有太多的数据库调优经验,我也不擅长编写 SQL。所以,我正在向有经验的开发人员征求每一条建议。任何建议将不胜感激。

a_horse_with_no_name

带有 OR 条件的(左)JOIN 通常没有得到很好的优化。但是您可以做的是在两列数组上创建一个索引,然后更改连接条件以使用数组运算符

首先创建索引:

create index on mjr_transaction_item using gin ( (array[src_id, dest_id]) );

然后更改 JOIN 条件:

...
FROM mjr_agent agnt
  LEFT JOIN mjr_transaction_item txi ON array[agnt.code] <@ array[txi.src_id, txi.dest_id] 
WHERE ...

您也可以使用 ANY 条件,但我认为这不会使用索引:

...
FROM mjr_agent agnt
  LEFT JOIN mjr_transaction_item txi ON agnt.code = ANY(array[txi.src_id, txi.dest_id]) 
WHERE ...

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在单个表上应用两列连接

来自分类Dev

连接两列并使用单个 sql 查询从它们的外键中获取字段值

来自分类Dev

连接R表中的两列

来自分类Dev

将两列的表连接到带有2个定界符的单个字符串中

来自分类Dev

使用SQL中的公共键将两个表/添加列连接到原始表

来自分类Dev

使用SQL中的公共键将两个表/添加列连接到原始表

来自分类Dev

连接单个字符并转换为c ++中的组合小数

来自分类Dev

如何从单个表中获取两列的最大值?

来自分类Dev

PostgreSQL连接获取表中的所有行,太慢

来自分类Dev

PostgreSQL连接获取表中的所有行,太慢

来自分类Dev

使用order by和limit-mysql在单个查询中更新两个不同表的两列

来自分类Dev

SQL内部连接来自两个表的具有单个用户标识的列

来自分类Dev

MYSQL将来自两个不同表的两个不同列连接为单个列

来自分类Dev

如何使用Xpath从表中提取所有带有连接单元格的行?

来自分类Dev

如何使用Xpath从表中提取所有带有连接单元格的行?

来自分类Dev

如何基于mysql中的两列连接表?

来自分类Dev

连接两个表并使用计算列

来自分类Dev

如何使内部连接两次到SQL Server中的单个表

来自分类Dev

逗号后的通配符列表并连接单个值

来自分类Dev

使用GROUP BY连接单列字段

来自分类Dev

使用单个查询重命名netezza中的两列

来自分类Dev

无法使用连接从两个表中获取数据

来自分类Dev

如何使用join连接sails中的两个表

来自分类Dev

使用 mySQL 列出两个连接表中的用户

来自分类Dev

如何从laravel中的表中使用两个外键从单个表中获取数据

来自分类Dev

MySQL使用连接表中的值更新单个表上的查询

来自分类Dev

如何使用单个更新查询交换表中的列值

来自分类Dev

两列引用另一个表中的单个列

来自分类Dev

MySQL使用SELECT合并单个表中的两个表

Related 相关文章

  1. 1

    如何在单个表上应用两列连接

  2. 2

    连接两列并使用单个 sql 查询从它们的外键中获取字段值

  3. 3

    连接R表中的两列

  4. 4

    将两列的表连接到带有2个定界符的单个字符串中

  5. 5

    使用SQL中的公共键将两个表/添加列连接到原始表

  6. 6

    使用SQL中的公共键将两个表/添加列连接到原始表

  7. 7

    连接单个字符并转换为c ++中的组合小数

  8. 8

    如何从单个表中获取两列的最大值?

  9. 9

    PostgreSQL连接获取表中的所有行,太慢

  10. 10

    PostgreSQL连接获取表中的所有行,太慢

  11. 11

    使用order by和limit-mysql在单个查询中更新两个不同表的两列

  12. 12

    SQL内部连接来自两个表的具有单个用户标识的列

  13. 13

    MYSQL将来自两个不同表的两个不同列连接为单个列

  14. 14

    如何使用Xpath从表中提取所有带有连接单元格的行?

  15. 15

    如何使用Xpath从表中提取所有带有连接单元格的行?

  16. 16

    如何基于mysql中的两列连接表?

  17. 17

    连接两个表并使用计算列

  18. 18

    如何使内部连接两次到SQL Server中的单个表

  19. 19

    逗号后的通配符列表并连接单个值

  20. 20

    使用GROUP BY连接单列字段

  21. 21

    使用单个查询重命名netezza中的两列

  22. 22

    无法使用连接从两个表中获取数据

  23. 23

    如何使用join连接sails中的两个表

  24. 24

    使用 mySQL 列出两个连接表中的用户

  25. 25

    如何从laravel中的表中使用两个外键从单个表中获取数据

  26. 26

    MySQL使用连接表中的值更新单个表上的查询

  27. 27

    如何使用单个更新查询交换表中的列值

  28. 28

    两列引用另一个表中的单个列

  29. 29

    MySQL使用SELECT合并单个表中的两个表

热门标签

归档