zoukankan      html  css  js  c++  java
  • 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
                        }
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  • 相关阅读:
    layer常用方法
    使用GLSL实现更多数量的局部光照 【转】
    GLSL实现简单硬件Anisotrop Lighting 【转】
    Bump mapping的GLSL实现 [转]
    图形化OpenGL调试器 BuGLe [转]
    GLSL实现Fresnel And Chromatic aberration 【转】
    GLSL实现Ambient Occlusion 【转】
    GLSL实现Glow效果 [转]
    2013年中国区Skyline软件价格体系
    [OSG]如何用Shader得到物体的世界坐标
  • 原文地址:https://www.cnblogs.com/zhjh256/p/15227767.html
Copyright © 2011-2022 走看看