• postgresql sql性能优化一例


    有如下一个SQL查询:

    SELECT DISTINCT
      u.* 
    FROM
      tsys_user u,
      tsys_user_right ur
      LEFT JOIN tsys_menu m ON m.trans_code = ur.trans_code
      LEFT JOIN tsys_trans tt ON m.menu_code = tt.trans_code 
      AND tt.model_code != '-1' 
    WHERE
      u.user_id = ur.user_id 
      AND ( u.approval_status IS NULL OR u.approval_status != '1' ) 
      AND ( ur.right_enable IS NULL OR ur.right_enable IN ( '', '1' ) ) 
      AND m.tree_idx LIKE concat( '','#bizroot#TCMP#', '%' )
      union 
    SELECT distinct u.* 
    FROM
      (select distinct m.tree_idx,rr.role_code,rr.right_flag,m.menu_code,rr.trans_code,rr.sub_trans_code from tsys_role_right rr
      LEFT JOIN tsys_menu m ON m.menu_code = rr.trans_code 
      LEFT JOIN tsys_trans tt ON m.menu_code = tt.trans_code AND tt.model_code != '-1' 
      where m.tree_idx LIKE concat( '','#bizroot#TCMP#', '%' )) as rr,
      tsys_user u,
      tsys_role r,
      tsys_role_user ru
    WHERE
      u.user_id = ru.user_code 
      AND rr.role_code = ru.role_code 
      AND rr.right_flag = ru.right_flag 
      AND rr.role_code = r.role_code 
      AND ( u.approval_status IS NULL OR u.approval_status != '1' ) 
      AND ( r.approval_status IS NULL OR r.approval_status != '1' ) 
      AND r.role_status = '1' 
      -- AND rr.tree_idx LIKE concat( '','#bizroot#scheduler_ui#', '%' )
      AND NOT EXISTS (
    SELECT
      'X' 
    FROM
      tsys_user_right ur 
    WHERE
      ur.trans_code = rr.trans_code 
      AND ur.sub_trans_code = rr.sub_trans_code 
      AND ur.right_flag = rr.right_flag 
      AND ur.right_enable = '0' 
      AND ur.user_id = u.user_id 
      );

    explain执行计划如下:

    QUERY PLAN                                                                                                                                                                                                                                                     |
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    HashAggregate  (cost=6333.49..6385.82 rows=5233 width=11792)                                                                                                                                                                                                   |
      Group Key: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.ext_field_4, u.|
      ->  Append  (cost=2251.18..5535.46 rows=5233 width=11792)                                                                                                                                                                                                    |
            ->  HashAggregate  (cost=2251.18..2296.72 rows=4554 width=174)                                                                                                                                                                                         |
                  Group Key: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.ext|
                  ->  Hash Join  (cost=353.81..1465.50 rows=5152 width=174)                                                                                                                                                                                        |
                        Hash Cond: ((ur.user_id)::text = (u.user_id)::text)                                                                                                                                                                                        |
                        ->  Hash Join  (cost=30.95..1129.11 rows=5152 width=5)                                                                                                                                                                                     |
                              Hash Cond: ((ur.trans_code)::text = (m.trans_code)::text)                                                                                                                                                                            |
                              ->  Seq Scan on tsys_user_right ur  (cost=0.00..904.24 rows=28480 width=26)                                                                                                                                                          |
                                    Filter: ((right_enable IS NULL) OR ((right_enable)::text = ANY ('{"",1}'::text[])))                                                                                                                                            |
                              ->  Hash  (cost=29.30..29.30 rows=132 width=44)                                                                                                                                                                                      |
                                    ->  Seq Scan on tsys_menu m  (cost=0.00..29.30 rows=132 width=44)                                                                                                                                                              |
                                          Filter: ((tree_idx)::text ~~ concat('', '#bizroot#TCMP#', '%'))                                                                                                                                                          |
                        ->  Hash  (cost=265.93..265.93 rows=4554 width=174)                                                                                                                                                                                        |
                              ->  Seq Scan on tsys_user u  (cost=0.00..265.93 rows=4554 width=174)                                                                                                                                                                 |
                                    Filter: ((approval_status IS NULL) OR ((approval_status)::text <> '1'::text))                                                                                                                                                  |
            ->  Unique  (cost=3055.00..3160.24 rows=679 width=174)                                                                                                                                                                                                 |
                  ->  Sort  (cost=3055.00..3056.70 rows=679 width=174)                                                                                                                                                                                             |
                        Sort Key: u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mobile, u_1.email, u_1.ext_flag, u_1.remark, u_1.ext_field_1, |
                        ->  Nested Loop Anti Join  (cost=1806.14..3023.06 rows=679 width=174)                                                                                                                                                                      |
                              Join Filter: ((ur_1.user_id)::text = (u_1.user_id)::text)                                                                                                                                                                            |
                              ->  Nested Loop  (cost=1805.85..2176.48 rows=683 width=216)                                                                                                                                                                          |
                                    ->  Merge Join  (cost=1805.57..1917.32 rows=683 width=47)                                                                                                                                                                      |
                                          Merge Cond: (((rr.right_flag)::text = (ru.right_flag)::text) AND ((rr.role_code)::text = (ru.role_code)::text))                                                                                                          |
                                          ->  Sort  (cost=836.65..842.51 rows=2345 width=55)                                                                                                                                                                       |
                                                Sort Key: rr.right_flag, rr.role_code                                                                                                                                                                              |
                                                ->  Hash Join  (cost=645.96..705.38 rows=2345 width=55)                                                                                                                                                            |
                                                      Hash Cond: ((rr.role_code)::text = (r.role_code)::text)                                                                                                                                                      |
                                                      ->  HashAggregate  (cost=637.04..663.24 rows=2620 width=130)                                                                                                                                                 |
                                                            Group Key: m_1.tree_idx, rr.role_code, rr.right_flag, m_1.menu_code, rr.trans_code, rr.sub_trans_code                                                                                                  |
                                                            ->  Hash Join  (cost=30.95..597.74 rows=2620 width=130)                                                                                                                                                |
                                                                  Hash Cond: ((rr.trans_code)::text = (m_1.menu_code)::text)                                                                                                                                       |
                                                                  ->  Seq Scan on tsys_role_right rr  (cost=0.00..513.63 rows=20163 width=48)                                                                                                                      |
                                                                  ->  Hash  (cost=29.30..29.30 rows=132 width=82)                                                                                                                                                  |
                                                                        ->  Seq Scan on tsys_menu m_1  (cost=0.00..29.30 rows=132 width=82)                                                                                                                        |
                                                                              Filter: ((tree_idx)::text ~~ concat('', '#bizroot#TCMP#', '%'))                                                                                                                      |
                                                      ->  Hash  (cost=6.69..6.69 rows=179 width=7)                                                                                                                                                                 |
                                                            ->  Seq Scan on tsys_role r  (cost=0.00..6.69 rows=179 width=7)                                                                                                                                        |
                                                                  Filter: (((approval_status IS NULL) OR ((approval_status)::text <> '1'::text)) AND ((role_status)::text = '1'::text))                                                                            |
                                          ->  Sort  (cost=968.92..998.03 rows=11645 width=13)                                                                                                                                                                      |
                                                Sort Key: ru.right_flag, ru.role_code                                                                                                                                                                              |
                                                ->  Seq Scan on tsys_role_user ru  (cost=0.00..182.45 rows=11645 width=13)                                                                                                                                         |
                                    ->  Index Scan using tsys_user_pkey on tsys_user u_1  (cost=0.28..0.38 rows=1 width=174)                                                                                                                                       |
                                          Index Cond: ((user_id)::text = (ru.user_code)::text)                                                                                                                                                                     |
                                          Filter: ((approval_status IS NULL) OR ((approval_status)::text <> '1'::text))                                                                                                                                            |
                              ->  Index Scan using idx_subcode_transcode on tsys_user_right ur_1  (cost=0.29..1.23 rows=1 width=58)                                                                                                                                |
                                    Index Cond: (((sub_trans_code)::text = (rr.sub_trans_code)::text) AND ((trans_code)::text = (rr.trans_code)::text))                                                                                                            |
                                    Filter: (((right_enable)::text = '0'::text) AND ((right_flag)::text = (rr.right_flag)::text))                                                                                                                                  |

    还是挺复杂的,具有性能优化的典型意义了。

    该语句要执行25秒左右,业务希望在1秒内。

    先来看下explain (analyze,verbose,buffers,settings)的情况:

    QUERY PLAN                                                                                                                                                                                                                                                     |
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    HashAggregate  (cost=2965.55..2974.38 rows=883 width=11792) (actual time=26462.092..26467.773 rows=3027 loops=1)                                                                                                                                               |
      Output: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.ext_field_4, u.use|
      Group Key: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.ext_field_4, u.|
      Batches: 1  Memory Usage: 1185kB                                                                                                                                                                                                                             |
      Buffers: shared hit=1501006                                                                                                                                                                                                                                  |
      ->  Append  (cost=1390.36..2830.90 rows=883 width=11792) (actual time=5.465..26439.559 rows=3028 loops=1)                                                                                                                                                    |
            Buffers: shared hit=1501006                                                                                                                                                                                                                            |
            ->  HashAggregate  (cost=1390.36..1398.17 rows=781 width=174) (actual time=5.463..5.489 rows=10 loops=1)                                                                                                                                               |
                  Output: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.ext_fi|
                  Group Key: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.ext|
                  Batches: 1  Memory Usage: 97kB                                                                                                                                                                                                                   |
                  Buffers: shared hit=815                                                                                                                                                                                                                          |
                  ->  Nested Loop  (cost=0.69..1271.26 rows=781 width=174) (actual time=0.362..3.320 rows=235 loops=1)                                                                                                                                             |
                        Output: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field_3, u.|
                        Inner Unique: true                                                                                                                                                                                                                         |
                        Buffers: shared hit=815                                                                                                                                                                                                                    |
                        ->  Nested Loop  (cost=0.41..1010.44 rows=781 width=5) (actual time=0.344..1.265 rows=235 loops=1)                                                                                                                                         |
                              Output: ur.user_id                                                                                                                                                                                                                   |
                              Buffers: shared hit=110                                                                                                                                                                                                              |
                              ->  Seq Scan on public.tsys_menu m  (cost=0.00..29.30 rows=20 width=44) (actual time=0.308..0.667 rows=21 loops=1)                                                                                                                   |
                                    Output: m.menu_code, m.kind_code, m.trans_code, m.sub_trans_code, m.menu_name, m.menu_arg, m.menu_icon, m.menu_url, m.window_type, m.window_model, m.tip, m.hot_key, m.parent_code, m.order_no, m.open_flag, m.tree_idx, m.rema|
                                    Filter: ((m.tree_idx)::text ~~ concat('', '#bizroot#scheduler_ui#', '%'))                                                                                                                                                      |
                                    Rows Removed by Filter: 466                                                                                                                                                                                                    |
                                    Buffers: shared hit=22                                                                                                                                                                                                         |
                              ->  Index Scan using tsys_user_right_pkey on public.tsys_user_right ur  (cost=0.41..48.67 rows=39 width=26) (actual time=0.014..0.025 rows=11 loops=21)                                                                              |
                                    Output: ur.trans_code, ur.sub_trans_code, ur.user_id, ur.create_by, ur.create_date, ur.begin_date, ur.end_date, ur.right_flag, ur.right_enable, ur.module_type, ur.action_type, ur.tenant_uuid, ur.tenant_id, ur.kind_code     |
                                    Index Cond: ((ur.trans_code)::text = (m.trans_code)::text)                                                                                                                                                                     |
                                    Filter: ((ur.right_enable IS NULL) OR ((ur.right_enable)::text = ANY ('{"",1}'::text[])))                                                                                                                                      |
                                    Buffers: shared hit=88                                                                                                                                                                                                         |
                        ->  Index Scan using tsys_user_pkey on public.tsys_user u  (cost=0.28..0.33 rows=1 width=174) (actual time=0.007..0.007 rows=1 loops=235)                                                                                                  |
                              Output: u.user_id, u.user_name, u.user_pwd, u.org_id, u.user_type, u.user_status, u.lock_status, u.create_date, u.modify_date, u.pass_modify_date, u.mobile, u.email, u.ext_flag, u.remark, u.ext_field_1, u.ext_field_2, u.ext_field|
                              Index Cond: ((u.user_id)::text = (ur.user_id)::text)                                                                                                                                                                                 |
                              Filter: ((u.approval_status IS NULL) OR ((u.approval_status)::text <> '1'::text))                                                                                                                                                    |
                              Buffers: shared hit=705                                                                                                                                                                                                              |
            ->  Unique  (cost=1403.67..1419.48 rows=102 width=174) (actual time=25277.599..26433.641 rows=3018 loops=1)                                                                                                                                            |
                  Output: u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mobile, u_1.email, u_1.ext_flag, u_1.remark, u_1.ext_field_1, u_1.ext_|
                  Buffers: shared hit=1500191                                                                                                                                                                                                                      |
                  ->  Sort  (cost=1403.67..1403.92 rows=102 width=174) (actual time=25277.594..25312.647 rows=271080 loops=1)                                                                                                                                      |
                        Output: u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mobile, u_1.email, u_1.ext_flag, u_1.remark, u_1.ext_field_1, u_|
                        Sort Key: u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mobile, u_1.email, u_1.ext_flag, u_1.remark, u_1.ext_field_1, |
                        Sort Method: quicksort  Memory: 84491kB                                                                                                                                                                                                    |
                        Buffers: shared hit=1500191                                                                                                                                                                                                                |
                        ->  Nested Loop Anti Join  (cost=168.33..1400.26 rows=102 width=174) (actual time=2.006..6410.412 rows=271080 loops=1)                                                                                                                     |
                              Output: u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mobile, u_1.email, u_1.ext_flag, u_1.remark, u_1.ext_field|
                              Join Filter: ((ur_1.user_id)::text = (u_1.user_id)::text)                                                                                                                                                                            |
                              Buffers: shared hit=1500191                                                                                                                                                                                                          |
                              ->  Nested Loop  (cost=168.04..981.77 rows=103 width=216) (actual time=1.982..2942.376 rows=271080 loops=1)                                                                                                                          |
                                    Output: rr.right_flag, rr.trans_code, rr.sub_trans_code, u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mob|
                                    Inner Unique: true                                                                                                                                                                                                             |
                                    Buffers: shared hit=813455                                                                                                                                                                                                     |
                                    ->  Merge Join  (cost=167.76..942.69 rows=103 width=47) (actual time=1.963..388.239 rows=271080 loops=1)                                                                                                                       |
                                          Output: rr.right_flag, rr.trans_code, rr.sub_trans_code, ru.user_code                                                                                                                                                    |
                                          Merge Cond: ((ru.right_flag)::text = (rr.right_flag)::text)                                                                                                                                                              |
                                          Join Filter: ((rr.role_code)::text = (ru.role_code)::text)                                                                                                                                                               |
                                          Rows Removed by Join Filter: 252945                                                                                                                                                                                      |
                                          Buffers: shared hit=215                                                                                                                                                                                                  |
                                          ->  Index Scan using indx_biz_roleuser_flag on public.tsys_role_user ru  (cost=0.29..384.38 rows=11645 width=13) (actual time=0.083..7.860 rows=11645 loops=1)                                                           |
                                                Output: ru.user_code, ru.role_code, ru.right_flag, ru.status                                                                                                                                                       |
                                                Buffers: shared hit=124                                                                                                                                                                                            |
                                          ->  Sort  (cost=167.47..168.36 rows=355 width=55) (actual time=1.474..63.049 rows=520948 loops=1)                                                                                                                        |
                                                Output: rr.role_code, rr.right_flag, rr.trans_code, rr.sub_trans_code, r.role_code                                                                                                                                 |
                                                Sort Key: rr.right_flag                                                                                                                                                                                            |
                                                Sort Method: quicksort  Memory: 38kB                                                                                                                                                                               |
                                                Buffers: shared hit=91                                                                                                                                                                                             |
                                                ->  Hash Join  (cost=143.43..152.44 rows=355 width=55) (actual time=1.315..1.421 rows=90 loops=1)                                                                                                                  |
                                                      Output: rr.role_code, rr.right_flag, rr.trans_code, rr.sub_trans_code, r.role_code                                                                                                                           |
                                                      Inner Unique: true                                                                                                                                                                                           |
                                                      Hash Cond: ((rr.role_code)::text = (r.role_code)::text)                                                                                                                                                      |
                                                      Buffers: shared hit=91                                                                                                                                                                                       |
                                                      ->  HashAggregate  (cost=134.51..138.48 rows=397 width=130) (actual time=1.081..1.128 rows=90 loops=1)                                                                                                       |
                                                            Output: m_1.tree_idx, rr.role_code, rr.right_flag, m_1.menu_code, rr.trans_code, rr.sub_trans_code                                                                                                     |
                                                            Group Key: m_1.tree_idx, rr.role_code, rr.right_flag, m_1.menu_code, rr.trans_code, rr.sub_trans_code                                                                                                  |
                                                            Batches: 1  Memory Usage: 61kB                                                                                                                                                                         |
                                                            Buffers: shared hit=87                                                                                                                                                                                 |
                                                            ->  Nested Loop  (cost=0.41..128.56 rows=397 width=130) (actual time=0.313..0.936 rows=90 loops=1)                                                                                                     |
                                                                  Output: m_1.tree_idx, rr.role_code, rr.right_flag, m_1.menu_code, rr.trans_code, rr.sub_trans_code                                                                                               |
                                                                  Buffers: shared hit=87                                                                                                                                                                           |
                                                                  ->  Seq Scan on public.tsys_menu m_1  (cost=0.00..29.30 rows=20 width=82) (actual time=0.284..0.621 rows=21 loops=1)                                                                             |
                                                                        Output: m_1.menu_code, m_1.kind_code, m_1.trans_code, m_1.sub_trans_code, m_1.menu_name, m_1.menu_arg, m_1.menu_icon, m_1.menu_url, m_1.window_type, m_1.window_model, m_1.tip, m_1.hot_key|
                                                                        Filter: ((m_1.tree_idx)::text ~~ concat('', '#bizroot#scheduler_ui#', '%'))                                                                                                                |
                                                                        Rows Removed by Filter: 466                                                                                                                                                                |
                                                                        Buffers: shared hit=22                                                                                                                                                                     |
                                                                  ->  Index Only Scan using tsys_role_right_pkey on public.tsys_role_right rr  (cost=0.41..4.76 rows=20 width=48) (actual time=0.011..0.013 rows=4 loops=21)                                       |
                                                                        Output: rr.trans_code, rr.sub_trans_code, rr.role_code, rr.begin_date, rr.end_date, rr.right_flag                                                                                          |
                                                                        Index Cond: (rr.trans_code = (m_1.menu_code)::text)                                                                                                                                        |
                                                                        Heap Fetches: 0                                                                                                                                                                            |
                                                                        Buffers: shared hit=65                                                                                                                                                                     |
                                                      ->  Hash  (cost=6.69..6.69 rows=179 width=7) (actual time=0.222..0.224 rows=179 loops=1)                                                                                                                     |
                                                            Output: r.role_code                                                                                                                                                                                    |
                                                            Buckets: 1024  Batches: 1  Memory Usage: 15kB                                                                                                                                                          |
                                                            Buffers: shared hit=4                                                                                                                                                                                  |
                                                            ->  Seq Scan on public.tsys_role r  (cost=0.00..6.69 rows=179 width=7) (actual time=0.011..0.130 rows=179 loops=1)                                                                                     |
                                                                  Output: r.role_code                                                                                                                                                                              |
                                                                  Filter: (((r.approval_status IS NULL) OR ((r.approval_status)::text <> '1'::text)) AND ((r.role_status)::text = '1'::text))                                                                      |
                                                                  Buffers: shared hit=4                                                                                                                                                                            |
                                    ->  Index Scan using tsys_user_pkey on public.tsys_user u_1  (cost=0.28..0.38 rows=1 width=174) (actual time=0.008..0.008 rows=1 loops=271080)                                                                                 |
                                          Output: u_1.user_id, u_1.user_name, u_1.user_pwd, u_1.org_id, u_1.user_type, u_1.user_status, u_1.lock_status, u_1.create_date, u_1.modify_date, u_1.pass_modify_date, u_1.mobile, u_1.email, u_1.ext_flag, u_1.remark, u|
                                          Index Cond: ((u_1.user_id)::text = (ru.user_code)::text)                                                                                                                                                                 |
                                          Filter: ((u_1.approval_status IS NULL) OR ((u_1.approval_status)::text <> '1'::text))                                                                                                                                    |
                                          Buffers: shared hit=813240                                                                                                                                                                                               |
                              ->  Index Scan using idx_subcode_transcode on public.tsys_user_right ur_1  (cost=0.29..4.05 rows=1 width=58) (actual time=0.011..0.011 rows=0 loops=271080)                                                                          |
                                    Output: ur_1.trans_code, ur_1.sub_trans_code, ur_1.user_id, ur_1.create_by, ur_1.create_date, ur_1.begin_date, ur_1.end_date, ur_1.right_flag, ur_1.right_enable, ur_1.module_type, ur_1.action_type, ur_1.tenant_uuid, ur_1.te|
                                    Index Cond: (((ur_1.sub_trans_code)::text = (rr.sub_trans_code)::text) AND ((ur_1.trans_code)::text = (rr.trans_code)::text))                                                                                                  |
                                    Filter: (((ur_1.right_enable)::text = '0'::text) AND ((ur_1.right_flag)::text = (rr.right_flag)::text))                                                                                                                        |
                                    Rows Removed by Filter: 5                                                                                                                                                                                                      |
                                    Buffers: shared hit=686736                                                                                                                                                                                                     |
    Settings: effective_cache_size = '128GB', enable_partitionwise_aggregate = 'on', enable_partitionwise_join = 'on', jit_above_cost = '1e+06', jit_inline_above_cost = '50000', jit_optimize_above_cost = '50000', max_parallel_workers_per_gather = '4', min_par|
    Planning:                                                                                                                                                                                                                                                      |
      Buffers: shared hit=108                                                                                                                                                                                                                                      |
    Planning Time: 7.923 ms                                                                                                                                                                                                                                        |
    Execution Time: 26509.953 ms                                                                                                                                                                                                                                   |

      首先就该语句来说,work_mem、shared_buffers、effective_cache_size已足够大,所以不存在物理I/O瓶颈。应用不好拆分SQL语句修改,重点在执行计划本身的优化上了(不要说SQL这么复杂不合理,我们做自研数据库LightDB开发,客户原来用oracle,所以我们的目标就是跟oracle一样性能高效,尽可能支持各种优化器策略和算法)。

      SQL优化在原生pg中就只有3个策略:1、优化器特性开关;2、SQL语句利用某些语义限制(如left join、distinct&order by子查询)重写;3、加减索引。或者借用pg_hint_plan,因为pg_hint_plan支持通过Set(k v)优化器提示修改GUC参数,所以可以认为覆盖了1(LightDB默认集成了pg_hint_plan,无需额外安装,直接可用)。

      下面我们分析上述执行计划:

       1、针对tsys_user_right表idx_subcode_transcode索引的anti join,走了nl,扫描次数太多,所以这个不应该走嵌套循环。可以通过set enable_nestloop=off;禁用,或/*+ Set(enable_nestloop off)*/。

      2、merge join一般也不建议使用,所以也先禁用。

      3、排序占用了太多的时间,但是返回的是user,所以可以先返回user_id,这样不用整个结果集排序,只要id即可,肯定更快。

    explain (analyze,buffers)
    with rr as materialized (
    select
        distinct m.tree_idx,
        rr.role_code,
        rr.right_flag,
        m.menu_code,
        rr.trans_code,
        rr.sub_trans_code
    from
        tsys_role_right rr
    left join tsys_menu m on
        m.menu_code = rr.trans_code
    left join tsys_trans tt on
        m.menu_code = tt.trans_code
        and tt.model_code != '-1'
    where
        m.tree_idx like concat( '', '#bizroot#BIZFRAME#', '%' ))
    select * from tsys_user tu where tu.user_id  in (
    select
      u.user_id
    from
        tsys_user u,
        tsys_user_right ur
    left join tsys_menu m on
        m.trans_code = ur.trans_code
    left join tsys_trans tt on
        m.menu_code = tt.trans_code
        and tt.model_code != '-1'
    where
        u.user_id = ur.user_id
        and ( u.approval_status is null
            or u.approval_status != '1' )
        and ( ur.right_enable is null
            or ur.right_enable in ( '', '1' ) )
        and m.tree_idx like concat( '', '#bizroot#BIZFRAME#', '%' )
    union
    select
        u.user_id
    from
        rr,
        tsys_user u,
        tsys_role r,
        tsys_role_user ru
    where
        u.user_id = ru.user_code
        and rr.role_code = ru.role_code
        and rr.right_flag = ru.right_flag
        and rr.role_code = r.role_code
        and ( u.approval_status is null
            or u.approval_status != '1' )
        and ( r.approval_status is null
            or r.approval_status != '1' )
        and r.role_status = '1'
        -- AND rr.tree_idx LIKE concat( '','#bizroot#scheduler_ui#', '%' )
        and not exists (
        select
            'X'
        from
            tsys_user_right ur
        where
            ur.trans_code = rr.trans_code
            and ur.sub_trans_code = rr.sub_trans_code
            and ur.right_flag = rr.right_flag
            and ur.right_enable = '0'
            and ur.user_id = u.user_id 
      ));
      
     
    QUERY PLAN                                                                                                                                                                                                                                                   |
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    Hash Join  (cost=4616.35..4882.86 rows=883 width=174) (actual time=202.367..204.116 rows=3027 loops=1)                                                                                                                                                       |
      Hash Cond: ((tu.user_id)::text = (u.user_id)::text)                                                                                                                                                                                                        |
      Buffers: shared hit=2083                                                                                                                                                                                                                                   |
      CTE rr                                                                                                                                                                                                                                                     |
        ->  HashAggregate  (cost=602.29..606.26 rows=397 width=130) (actual time=2.576..2.598 rows=90 loops=1)                                                                                                                                                   |
              Group Key: m_1.tree_idx, rr_1.role_code, rr_1.right_flag, m_1.menu_code, rr_1.trans_code, rr_1.sub_trans_code                                                                                                                                      |
              Batches: 1  Memory Usage: 61kB                                                                                                                                                                                                                     |
              Buffers: shared hit=334                                                                                                                                                                                                                            |
              ->  Hash Join  (cost=29.55..596.34 rows=397 width=130) (actual time=1.550..2.538 rows=90 loops=1)                                                                                                                                                  |
                    Hash Cond: ((rr_1.trans_code)::text = (m_1.menu_code)::text)                                                                                                                                                                                 |
                    Buffers: shared hit=334                                                                                                                                                                                                                      |
                    ->  Seq Scan on tsys_role_right rr_1  (cost=0.00..513.63 rows=20163 width=48) (actual time=0.002..0.869 rows=20163 loops=1)                                                                                                                  |
                          Buffers: shared hit=312                                                                                                                                                                                                                |
                    ->  Hash  (cost=29.30..29.30 rows=20 width=82) (actual time=0.150..0.151 rows=21 loops=1)                                                                                                                                                    |
                          Buckets: 1024  Batches: 1  Memory Usage: 11kB                                                                                                                                                                                          |
                          Buffers: shared hit=22                                                                                                                                                                                                                 |
                          ->  Seq Scan on tsys_menu m_1  (cost=0.00..29.30 rows=20 width=82) (actual time=0.068..0.146 rows=21 loops=1)                                                                                                                          |
                                Filter: ((tree_idx)::text ~~ concat('', '#bizroot#scheduler_ui#', '%'))                                                                                                                                                          |
                                Rows Removed by Filter: 466                                                                                                                                                                                                      |
                                Buffers: shared hit=22                                                                                                                                                                                                           |
      ->  Seq Scan on tsys_user tu  (cost=0.00..254.54 rows=4554 width=174) (actual time=0.039..0.242 rows=4554 loops=1)                                                                                                                                         |
            Buffers: shared hit=209                                                                                                                                                                                                                              |
      ->  Hash  (cost=3999.06..3999.06 rows=883 width=82) (actual time=202.319..202.327 rows=3027 loops=1)                                                                                                                                                       |
            Buckets: 4096 (originally 1024)  Batches: 1 (originally 1)  Memory Usage: 145kB                                                                                                                                                                      |
            Buffers: shared hit=1874                                                                                                                                                                                                                             |
            ->  HashAggregate  (cost=3981.40..3990.23 rows=883 width=82) (actual time=201.774..201.994 rows=3027 loops=1)                                                                                                                                        |
                  Group Key: u.user_id                                                                                                                                                                                                                           |
                  Batches: 1  Memory Usage: 369kB                                                                                                                                                                                                                |
                  Buffers: shared hit=1874                                                                                                                                                                                                                       |
                  ->  Append  (cost=352.41..3979.19 rows=883 width=82) (actual time=4.622..176.174 rows=271315 loops=1)                                                                                                                                          |
                        Buffers: shared hit=1874                                                                                                                                                                                                                 |
                        ->  Hash Join  (cost=352.41..1408.90 rows=781 width=5) (actual time=4.621..7.484 rows=235 loops=1)                                                                                                                                       |
                              Hash Cond: ((ur.user_id)::text = (u.user_id)::text)                                                                                                                                                                                |
                              Buffers: shared hit=746                                                                                                                                                                                                            |
                              ->  Hash Join  (cost=29.55..1084.00 rows=781 width=5) (actual time=3.130..5.959 rows=235 loops=1)                                                                                                                                  |
                                    Hash Cond: ((ur.trans_code)::text = (m.trans_code)::text)                                                                                                                                                                    |
                                    Buffers: shared hit=537                                                                                                                                                                                                      |
                                    ->  Seq Scan on tsys_user_right ur  (cost=0.00..904.24 rows=28480 width=26) (actual time=0.005..4.247 rows=28470 loops=1)                                                                                                    |
                                          Filter: ((right_enable IS NULL) OR ((right_enable)::text = ANY ('{"",1}'::text[])))                                                                                                                                    |
                                          Rows Removed by Filter: 2669                                                                                                                                                                                           |
                                          Buffers: shared hit=515                                                                                                                                                                                                |
                                    ->  Hash  (cost=29.30..29.30 rows=20 width=44) (actual time=0.159..0.159 rows=21 loops=1)                                                                                                                                    |
                                          Buckets: 1024  Batches: 1  Memory Usage: 10kB                                                                                                                                                                          |
                                          Buffers: shared hit=22                                                                                                                                                                                                 |
                                          ->  Seq Scan on tsys_menu m  (cost=0.00..29.30 rows=20 width=44) (actual time=0.073..0.153 rows=21 loops=1)                                                                                                            |
                                                Filter: ((tree_idx)::text ~~ concat('', '#bizroot#scheduler_ui#', '%'))                                                                                                                                          |
                                                Rows Removed by Filter: 466                                                                                                                                                                                      |
                                                Buffers: shared hit=22                                                                                                                                                                                           |
                              ->  Hash  (cost=265.93..265.93 rows=4554 width=5) (actual time=1.475..1.476 rows=4554 loops=1)                                                                                                                                     |
                                    Buckets: 8192  Batches: 1  Memory Usage: 231kB                                                                                                                                                                               |
                                    Buffers: shared hit=209                                                                                                                                                                                                      |
                                    ->  Seq Scan on tsys_user u  (cost=0.00..265.93 rows=4554 width=5) (actual time=0.031..1.099 rows=4554 loops=1)                                                                                                              |
                                          Filter: ((approval_status IS NULL) OR ((approval_status)::text <> '1'::text))                                                                                                                                          |
                                          Buffers: shared hit=209                                                                                                                                                                                                |
                        ->  Hash Anti Join  (cost=2270.29..2557.04 rows=102 width=5) (actual time=87.087..156.701 rows=271080 loops=1)                                                                                                                           |
                              Hash Cond: (((rr.trans_code)::text = (ur_1.trans_code)::text) AND ((rr.sub_trans_code)::text = (ur_1.sub_trans_code)::text) AND ((rr.right_flag)::text = (ur_1.right_flag)::text) AND ((u_1.user_id)::text = (ur_1.user_id)::text))|
                              Buffers: shared hit=1128                                                                                                                                                                                                           |
                              ->  Hash Join  (cost=1314.29..1598.33 rows=103 width=875) (actual time=83.114..113.969 rows=271080 loops=1)                                                                                                                        |
                                    Hash Cond: ((u_1.user_id)::text = (ru.user_code)::text)                                                                                                                                                                      |
                                    Buffers: shared hit=613                                                                                                                                                                                                      |
                                    ->  Seq Scan on tsys_user u_1  (cost=0.00..265.93 rows=4554 width=5) (actual time=0.025..1.282 rows=4554 loops=1)                                                                                                            |
                                          Filter: ((approval_status IS NULL) OR ((approval_status)::text <> '1'::text))                                                                                                                                          |
                                          Buffers: shared hit=209                                                                                                                                                                                                |
                                    ->  Hash  (cost=1313.01..1313.01 rows=103 width=875) (actual time=83.081..83.084 rows=271080 loops=1)                                                                                                                        |
                                          Buckets: 524288 (originally 1024)  Batches: 1 (originally 1)  Memory Usage: 30277kB                                                                                                                                    |
                                          Buffers: shared hit=404                                                                                                                                                                                                |
                                          ->  Hash Join  (cost=23.25..1313.01 rows=103 width=875) (actual time=2.730..31.974 rows=271080 loops=1)                                                                                                                |
                                                Hash Cond: (((ru.role_code)::text = (rr.role_code)::text) AND ((ru.right_flag)::text = (rr.right_flag)::text))                                                                                                   |
                                                Buffers: shared hit=404                                                                                                                                                                                          |
                                                ->  Seq Scan on tsys_role_user ru  (cost=0.00..182.45 rows=11645 width=13) (actual time=0.002..0.527 rows=11645 loops=1)                                                                                         |
                                                      Buffers: shared hit=66                                                                                                                                                                                     |
                                                ->  Hash  (cost=17.93..17.93 rows=355 width=1023) (actual time=2.718..2.720 rows=90 loops=1)                                                                                                                     |
                                                      Buckets: 1024  Batches: 1  Memory Usage: 18kB                                                                                                                                                              |
                                                      Buffers: shared hit=338                                                                                                                                                                                    |
                                                      ->  Hash Join  (cost=8.92..17.93 rows=355 width=1023) (actual time=2.639..2.704 rows=90 loops=1)                                                                                                           |
                                                            Hash Cond: ((rr.role_code)::text = (r.role_code)::text)                                                                                                                                              |
                                                            Buffers: shared hit=338                                                                                                                                                                              |
                                                            ->  CTE Scan on rr  (cost=0.00..7.94 rows=397 width=1016) (actual time=2.578..2.624 rows=90 loops=1)                                                                                                 |
                                                                  Buffers: shared hit=334                                                                                                                                                                        |
                                                            ->  Hash  (cost=6.69..6.69 rows=179 width=7) (actual time=0.056..0.057 rows=179 loops=1)                                                                                                             |
                                                                  Buckets: 1024  Batches: 1  Memory Usage: 15kB                                                                                                                                                  |
                                                                  Buffers: shared hit=4                                                                                                                                                                          |
                                                                  ->  Seq Scan on tsys_role r  (cost=0.00..6.69 rows=179 width=7) (actual time=0.005..0.040 rows=179 loops=1)                                                                                    |
                                                                        Filter: (((approval_status IS NULL) OR ((approval_status)::text <> '1'::text)) AND ((role_status)::text = '1'::text))                                                                    |
                                                                        Buffers: shared hit=4                                                                                                                                                                    |
                              ->  Hash  (cost=904.24..904.24 rows=2588 width=58) (actual time=3.945..3.946 rows=2596 loops=1)                                                                                                                                    |
                                    Buckets: 4096  Batches: 1  Memory Usage: 258kB                                                                                                                                                                               |
                                    Buffers: shared hit=515                                                                                                                                                                                                      |
                                    ->  Seq Scan on tsys_user_right ur_1  (cost=0.00..904.24 rows=2588 width=58) (actual time=0.038..3.372 rows=2596 loops=1)                                                                                                    |
                                          Filter: ((right_enable)::text = '0'::text)                                                                                                                                                                             |
                                          Rows Removed by Filter: 28543                                                                                                                                                                                          |
                                          Buffers: shared hit=515                                                                                                                                                                                                |
    Planning Time: 1.028 ms                                                                                                                                                                                                                                      |
    Execution Time: 204.836 ms                                                                                                                                                                                                                                   |

    调整之后,针对scheduler_ui的查询已经很快了,300毫秒。针对另外一个条件XAFB则为1.7秒。但是到了默认的frame,还要10秒。如下:

    QUERY PLAN                                                                                                                                                                                                                                             |
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    Hash Join  (cost=16299.80..16528.72 rows=10117 width=174) (actual time=9944.104..9947.221 rows=4369 loops=1)                                                                                                                                           |
      Hash Cond: ((u.user_id)::text = (tu.user_id)::text)                                                                                                                                                                                                  |
      Buffers: shared hit=2083                                                                                                                                                                                                                             |
      CTE rr                                                                                                                                                                                                                                               |
        ->  HashAggregate  (cost=667.12..712.57 rows=4545 width=130) (actual time=7.432..9.842 rows=9476 loops=1)                                                                                                                                          |
              Group Key: m_1.tree_idx, rr_1.role_code, rr_1.right_flag, m_1.menu_code, rr_1.trans_code, rr_1.sub_trans_code                                                                                                                                |
              Batches: 1  Memory Usage: 2449kB                                                                                                                                                                                                             |
              Buffers: shared hit=334                                                                                                                                                                                                                      |
              ->  Hash Join  (cost=32.17..598.95 rows=4545 width=130) (actual time=0.203..3.934 rows=9476 loops=1)                                                                                                                                         |
                    Hash Cond: ((rr_1.trans_code)::text = (m_1.menu_code)::text)                                                                                                                                                                           |
                    Buffers: shared hit=334                                                                                                                                                                                                                |
                    ->  Seq Scan on tsys_role_right rr_1  (cost=0.00..513.63 rows=20163 width=48) (actual time=0.003..0.928 rows=20163 loops=1)                                                                                                            |
                          Buffers: shared hit=312                                                                                                                                                                                                          |
                    ->  Hash  (cost=29.30..29.30 rows=229 width=82) (actual time=0.176..0.177 rows=227 loops=1)                                                                                                                                            |
                          Buckets: 1024  Batches: 1  Memory Usage: 32kB                                                                                                                                                                                    |
                          Buffers: shared hit=22                                                                                                                                                                                                           |
                          ->  Seq Scan on tsys_menu m_1  (cost=0.00..29.30 rows=229 width=82) (actual time=0.008..0.143 rows=227 loops=1)                                                                                                                  |
                                Filter: ((tree_idx)::text ~~ concat('', '#bizroot#BIZFRAME#', '%'))                                                                                                                                                        |
                                Rows Removed by Filter: 260                                                                                                                                                                                                |
                                Buffers: shared hit=22                                                                                                                                                                                                     |
      ->  HashAggregate  (cost=15275.77..15376.94 rows=10117 width=82) (actual time=9943.152..9943.637 rows=4369 loops=1)                                                                                                                                  |
            Group Key: u.user_id                                                                                                                                                                                                                           |
            Batches: 1  Memory Usage: 657kB                                                                                                                                                                                                                |
            Buffers: shared hit=1874                                                                                                                                                                                                                       |
            ->  Append  (cost=355.02..15250.47 rows=10117 width=82) (actual time=1.745..8185.464 rows=19452542 loops=1)                                                                                                                                    |
                  Buffers: shared hit=1874                                                                                                                                                                                                                 |
                  ->  Hash Join  (cost=355.02..1514.53 rows=8939 width=5) (actual time=1.743..8.721 rows=5199 loops=1)                                                                                                                                     |
                        Hash Cond: ((ur.user_id)::text = (u.user_id)::text)                                                                                                                                                                                |
                        Buffers: shared hit=746                                                                                                                                                                                                            |
                        ->  Hash Join  (cost=32.17..1168.20 rows=8939 width=5) (actual time=0.251..6.371 rows=5199 loops=1)                                                                                                                                |
                              Hash Cond: ((ur.trans_code)::text = (m.trans_code)::text)                                                                                                                                                                    |
                              Buffers: shared hit=537                                                                                                                                                                                                      |
                              ->  Seq Scan on tsys_user_right ur  (cost=0.00..904.24 rows=28480 width=26) (actual time=0.006..4.213 rows=28470 loops=1)                                                                                                    |
                                    Filter: ((right_enable IS NULL) OR ((right_enable)::text = ANY ('{"",1}'::text[])))                                                                                                                                    |
                                    Rows Removed by Filter: 2669                                                                                                                                                                                           |
                                    Buffers: shared hit=515                                                                                                                                                                                                |
                              ->  Hash  (cost=29.30..29.30 rows=229 width=44) (actual time=0.207..0.208 rows=227 loops=1)                                                                                                                                  |
                                    Buckets: 1024  Batches: 1  Memory Usage: 24kB                                                                                                                                                                          |
                                    Buffers: shared hit=22                                                                                                                                                                                                 |
                                    ->  Seq Scan on tsys_menu m  (cost=0.00..29.30 rows=229 width=44) (actual time=0.008..0.167 rows=227 loops=1)                                                                                                          |
                                          Filter: ((tree_idx)::text ~~ concat('', '#bizroot#BIZFRAME#', '%'))                                                                                                                                              |
                                          Rows Removed by Filter: 260                                                                                                                                                                                      |
                                          Buffers: shared hit=22                                                                                                                                                                                           |
                        ->  Hash  (cost=265.93..265.93 rows=4554 width=5) (actual time=1.456..1.457 rows=4554 loops=1)                                                                                                                                     |
                              Buckets: 8192  Batches: 1  Memory Usage: 231kB                                                                                                                                                                               |
                              Buffers: shared hit=209                                                                                                                                                                                                      |
                              ->  Seq Scan on tsys_user u  (cost=0.00..265.93 rows=4554 width=5) (actual time=0.030..1.039 rows=4554 loops=1)                                                                                                              |
                                    Filter: ((approval_status IS NULL) OR ((approval_status)::text <> '1'::text))                                                                                                                                          |
                                    Buffers: shared hit=209                                                                                                                                                                                                |
                  ->  Hash Anti Join  (cost=1451.88..13584.19 rows=1178 width=5) (actual time=21.894..7401.208 rows=19447343 loops=1)                                                                                                                      |
                        Hash Cond: (((rr.trans_code)::text = (ur_1.trans_code)::text) AND ((rr.sub_trans_code)::text = (ur_1.sub_trans_code)::text) AND ((rr.right_flag)::text = (ur_1.right_flag)::text) AND ((u_1.user_id)::text = (ur_1.user_id)::text))|
                        Buffers: shared hit=1128                                                                                                                                                                                                           |
                        ->  Hash Join  (cost=495.88..12600.29 rows=1184 width=875) (actual time=17.965..4679.762 rows=19447423 loops=1)                                                                                                                    |
                              Hash Cond: ((ru.user_code)::text = (u_1.user_id)::text)                                                                                                                                                                      |
                              Buffers: shared hit=613                                                                                                                                                                                                      |
                              ->  Hash Join  (cost=173.03..12274.33 rows=1184 width=875) (actual time=16.476..2244.767 rows=19447511 loops=1)                                                                                                              |
                                    Hash Cond: (((ru.role_code)::text = (rr.role_code)::text) AND ((ru.right_flag)::text = (rr.right_flag)::text))                                                                                                         |
                                    Buffers: shared hit=404                                                                                                                                                                                                |
                                    ->  Seq Scan on tsys_role_user ru  (cost=0.00..182.45 rows=11645 width=13) (actual time=0.004..0.791 rows=11645 loops=1)                                                                                               |
                                          Buffers: shared hit=66                                                                                                                                                                                           |
                                    ->  Hash  (cost=112.01..112.01 rows=4068 width=1023) (actual time=16.456..16.459 rows=9472 loops=1)                                                                                                                    |
                                          Buckets: 16384 (originally 4096)  Batches: 1 (originally 1)  Memory Usage: 856kB                                                                                                                                 |
                                          Buffers: shared hit=338                                                                                                                                                                                          |
                                          ->  Hash Join  (cost=8.92..112.01 rows=4068 width=1023) (actual time=7.498..14.520 rows=9472 loops=1)                                                                                                            |
                                                Hash Cond: ((rr.role_code)::text = (r.role_code)::text)                                                                                                                                                    |
                                                Buffers: shared hit=338                                                                                                                                                                                    |
                                                ->  CTE Scan on rr  (cost=0.00..90.90 rows=4545 width=1016) (actual time=7.434..12.918 rows=9476 loops=1)                                                                                                  |
                                                      Buffers: shared hit=334                                                                                                                                                                              |
                                                ->  Hash  (cost=6.69..6.69 rows=179 width=7) (actual time=0.056..0.057 rows=179 loops=1)                                                                                                                   |
                                                      Buckets: 1024  Batches: 1  Memory Usage: 15kB                                                                                                                                                        |
                                                      Buffers: shared hit=4                                                                                                                                                                                |
                                                      ->  Seq Scan on tsys_role r  (cost=0.00..6.69 rows=179 width=7) (actual time=0.007..0.040 rows=179 loops=1)                                                                                          |
                                                            Filter: (((approval_status IS NULL) OR ((approval_status)::text <> '1'::text)) AND ((role_status)::text = '1'::text))                                                                          |
                                                            Buffers: shared hit=4                                                                                                                                                                          |
                              ->  Hash  (cost=265.93..265.93 rows=4554 width=5) (actual time=1.452..1.452 rows=4554 loops=1)                                                                                                                               |
                                    Buckets: 8192  Batches: 1  Memory Usage: 231kB                                                                                                                                                                         |
                                    Buffers: shared hit=209                                                                                                                                                                                                |
                                    ->  Seq Scan on tsys_user u_1  (cost=0.00..265.93 rows=4554 width=5) (actual time=0.019..0.972 rows=4554 loops=1)                                                                                                      |
                                          Filter: ((approval_status IS NULL) OR ((approval_status)::text <> '1'::text))                                                                                                                                    |
                                          Buffers: shared hit=209                                                                                                                                                                                          |
                        ->  Hash  (cost=904.24..904.24 rows=2588 width=58) (actual time=3.921..3.922 rows=2596 loops=1)                                                                                                                                    |
                              Buckets: 4096  Batches: 1  Memory Usage: 258kB                                                                                                                                                                               |
                              Buffers: shared hit=515                                                                                                                                                                                                      |
                              ->  Seq Scan on tsys_user_right ur_1  (cost=0.00..904.24 rows=2588 width=58) (actual time=0.026..3.316 rows=2596 loops=1)                                                                                                    |
                                    Filter: ((right_enable)::text = '0'::text)                                                                                                                                                                             |
                                    Rows Removed by Filter: 28543                                                                                                                                                                                          |
                                    Buffers: shared hit=515                                                                                                                                                                                                |
      ->  Hash  (cost=254.54..254.54 rows=4554 width=174) (actual time=0.933..0.934 rows=4554 loops=1)                                                                                                                                                     |
            Buckets: 8192  Batches: 1  Memory Usage: 971kB                                                                                                                                                                                                 |
            Buffers: shared hit=209                                                                                                                                                                                                                        |
            ->  Seq Scan on tsys_user tu  (cost=0.00..254.54 rows=4554 width=174) (actual time=0.040..0.309 rows=4554 loops=1)                                                                                                                             |
                  Buffers: shared hit=209                                                                                                                                                                                                                  |
    Planning Time: 0.996 ms                                                                                                                                                                                                                                |
    Execution Time: 9947.867 ms                                                                                                                                                                                                                            |

      hash join的这一步导致慢的根源,因为它的结果集大了,导致后面要么要建立哈希表、要么要扫描一遍,所以结果就会非常大。因此性能线性下降,后面每一次关联hash都要2秒2秒的增加,即使结果集很大,走哈希也不一定是个正确的路子。通过让再次优化,可以实现6.8秒。如下:

    explain (analyze)
        with rr as materialized (
    select
            distinct m.tree_idx,
            rr.role_code,
            rr.right_flag,
            m.menu_code,
            rr.trans_code,
            rr.sub_trans_code
    from
            tsys_role_right rr
    left join tsys_menu m on
            m.menu_code = rr.trans_code
    left join tsys_trans tt on
            m.menu_code = tt.trans_code
        and tt.model_code != '-1'
    where
            m.tree_idx like concat( '', '#bizroot#BIZFRAME#', '%' )),
    xxx as materialized (
                select distinct
                    ru.role_code ,
                    ru.right_flag,
                    u.user_id
                from
                    tsys_role r
                join tsys_role_user ru on
                    r.role_code = ru.role_code
                    and ( r.approval_status is null
                        or r.approval_status != '1' )
                    and r.role_status = '1'
                join tsys_user u on
                    u.user_id = ru.user_code
                    and ( u.approval_status is null
                        or u.approval_status != '1' ))
        select
        *
    from
        tsys_user tu
    where
        tu.user_id in (
        select
            u.user_id
        from
            tsys_user u,
            tsys_user_right ur
        left join tsys_menu m on
            m.trans_code = ur.trans_code
        left join tsys_trans tt on
            m.menu_code = tt.trans_code
            and tt.model_code != '-1'
        where
            u.user_id = ur.user_id
            and ( u.approval_status is null
                or u.approval_status != '1' )
            and ( ur.right_enable is null
                or ur.right_enable in ( '', '1' ) )
                and m.tree_idx like concat( '', '#bizroot#BIZFRAME#', '%' )
        union
            select 
                distinct xxx.user_id
            from
                xxx
            join 
            rr on
                rr.role_code = xxx.role_code
                and rr.right_flag = xxx.right_flag
            where
                -- AND rr.tree_idx LIKE concat( '','#bizroot#scheduler_ui#', '%' )
                -- and
            not exists (
                select
                    'X'
                from
                    tsys_user_right ur
                where
                    ur.trans_code = rr.trans_code
                    and ur.sub_trans_code = rr.sub_trans_code
                    and ur.right_flag = rr.right_flag
                    and ur.right_enable = '0'
                    and ur.user_id = xxx.user_id 
          ))

       GEQO也不智能。

      如果一下子无头绪,可以看一下相同的语句在oracle和mysql中的表现,如果它们两个很快,可以参考它们的执行计划,下面是mysql的,即使是BIZFRAME,也只要1秒钟。

    {
      "query_block": {
        "union_result": {
          "table_name": "<union1,2>",
          "access_type": "ALL",
          "query_specifications": [
            {
              "query_block": {
                "select_id": 1,
                "temporary_table": {
                  "table": {
                    "table_name": "m",
                    "access_type": "ALL",
                    "possible_keys": ["FK_MENU_SOURCE"],
                    "rows": 488,
                    "filtered": 100,
                    "attached_condition": "m.tree_idx like '#bizroot#BIZFRAME#%' and m.trans_code is not null"
                  },
                  "table": {
                    "table_name": "ur",
                    "access_type": "ref",
                    "possible_keys": ["PRIMARY", "FK_RIGHT_USER", "idx_user_id"],
                    "key": "PRIMARY",
                    "key_length": "602",
                    "used_key_parts": ["trans_code"],
                    "ref": ["bizframetcmp.m.trans_code"],
                    "rows": 25,
                    "filtered": 100,
                    "attached_condition": "ur.right_enable is null or ur.right_enable in ('','1')"
                  },
                  "table": {
                    "table_name": "u",
                    "access_type": "eq_ref",
                    "possible_keys": ["PRIMARY"],
                    "key": "PRIMARY",
                    "key_length": "98",
                    "used_key_parts": ["user_id"],
                    "ref": ["bizframetcmp.ur.user_id"],
                    "rows": 1,
                    "filtered": 100,
                    "attached_condition": "u.approval_status is null or u.approval_status <> '1'"
                  }
                }
              }
            },
            {
              "query_block": {
                "select_id": 2,
                "operation": "UNION",
                "temporary_table": {
                  "table": {
                    "table_name": "u",
                    "access_type": "ALL",
                    "possible_keys": ["PRIMARY"],
                    "rows": 4674,
                    "filtered": 100,
                    "attached_condition": "u.approval_status is null or u.approval_status <> '1'"
                  },
                  "table": {
                    "table_name": "ru",
                    "access_type": "ref",
                    "possible_keys": [
                      "PRIMARY",
                      "FK_ROLEUSER_ROLE",
                      "INDX_BIZ_ROLEUSER_FLAG",
                      "INDX_BIZ_ROLEUSER_RU"
                    ],
                    "key": "PRIMARY",
                    "key_length": "98",
                    "used_key_parts": ["user_code"],
                    "ref": ["bizframetcmp.u.user_id"],
                    "rows": 1,
                    "filtered": 100,
                    "using_index": true,
                    "distinct": true
                  },
                  "table": {
                    "table_name": "r",
                    "access_type": "eq_ref",
                    "possible_keys": ["PRIMARY"],
                    "key": "PRIMARY",
                    "key_length": "194",
                    "used_key_parts": ["role_code"],
                    "ref": ["bizframetcmp.ru.role_code"],
                    "rows": 1,
                    "filtered": 100,
                    "attached_condition": "(r.approval_status is null or r.approval_status <> '1') and r.role_status = '1'",
                    "distinct": true
                  },
                  "table": {
                    "table_name": "<derived3>",
                    "access_type": "ref",
                    "possible_keys": ["key1"],
                    "key": "key1",
                    "key_length": "220",
                    "used_key_parts": ["role_code", "right_flag"],
                    "ref": ["bizframetcmp.ru.role_code", "bizframetcmp.ru.right_flag"],
                    "rows": 19,
                    "filtered": 100,
                    "attached_condition": "rr.right_flag = ru.right_flag and !<in_optimizer>((rr.trans_code,rr.sub_trans_code,rr.right_flag,u.user_id),<exists>(subquery#4))",
                    "distinct": true,
                    "materialized": {
                      "query_block": {
                        "select_id": 3,
                        "temporary_table": {
                          "table": {
                            "table_name": "m",
                            "access_type": "ALL",
                            "possible_keys": ["PRIMARY", "INDX_BIZ_MENU_CODE"],
                            "rows": 488,
                            "filtered": 100,
                            "attached_condition": "m.tree_idx like '#bizroot#BIZFRAME#%'"
                          },
                          "table": {
                            "table_name": "rr",
                            "access_type": "ref",
                            "possible_keys": ["PRIMARY"],
                            "key": "PRIMARY",
                            "key_length": "602",
                            "used_key_parts": ["trans_code"],
                            "ref": ["bizframetcmp.m.menu_code"],
                            "rows": 7,
                            "filtered": 100,
                            "using_index": true
                          }
                        }
                      }
                    }
                  },
                  "subqueries": [
                    {
                      "query_block": {
                        "select_id": 4,
                        "table": {
                          "table_name": "ur",
                          "access_type": "index_subquery",
                          "possible_keys": [
                            "PRIMARY",
                            "FK_RIGHT_USER",
                            "idx_user_id",
                            "idx_subcode_transcode"
                          ],
                          "key": "PRIMARY",
                          "key_length": "1302",
                          "used_key_parts": ["trans_code", "sub_trans_code", "user_id"],
                          "ref": ["func", "func", "func"],
                          "rows": 1,
                          "filtered": 100
                        }
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  • 相关阅读:
    Android游戏开发22:Android动画的实现J2me游戏类库用于Android开发
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第三部分,完整代码)
    使用OGR创建dxf格式矢量数据
    mysql 数据库引擎 MyISAM InnoDB 大比拼 区别
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第二部分)
    mysql 更改数据库引擎
    android sqlite SQLiteDatabase 操作大全 不看后悔!必收藏!看后精通SQLITE (第一部分)
    android 数字键盘使用
    MySQL Innodb数据库性能实践
    eclipse : Error while performing database login with the driver null
  • 原文地址:https://www.cnblogs.com/zhjh256/p/15227767.html
Copyright © 2020-2023  润新知