1. 程式人生 > 其它 >KINGBASE Query Mapping 查詢對映功能

KINGBASE Query Mapping 查詢對映功能

有過SQL優化經歷的人都知道,對於有些SQL效能問題,可能需要涉及到SQL層面的修改,這不僅麻煩,而且在已上線的系統還存在很大的風險。KINGBASE V8R6 提供了query mapping功能,使用者可以通過SQL對映,可以避免直接修改SQL的過程。

以下以舉例介紹query mapping 的功能及使用。

一、設定功能開關引數

query mapping 功能開啟與否,是通過引數enable_query_rule 控制的。設定enable_query_rule = on ,開啟query mapping功能。

二、使用例子

1、準備資料

create table t1(id integer
,name varchar(9)); insert into t1 select generate_series(1,1000000),'a'||generate_series(1000001,2000000); create index ind_t1_name on t1(name); create view v_t1 as select id,upper(name) name from t1;

例子建了個檢視,檢視對於索引列做了upper操作。upper 操作使得原有的索引無法使用。

2、Mapping前SQL 執行計劃分析

假設應用有這麼一條SQL :select id from v_t1 where name=$1; 可以看下執行計劃:由於做了upper轉換,無法使用索引。

test=# explain select id from v_t1 where name='A1234567';
                                         QUERY PLAN                                         
--------------------------------------------------------------------------------------------
 Seq Scan on t1  (cost=0.00..22906.00 rows=5000 width=4)
   Filter: (((
upper((name)::text))::character varying(8000 char))::text = 'A1234567'::text)

如果需要使用索引,只能修改SQL,直接查詢表。可以看下執行計劃:索引訪問

test=# explain select id from t1 where name=lower('A1234567');
                              QUERY PLAN                              
----------------------------------------------------------------------
 Index Scan using ind_t1_name on t1  (cost=0.42..8.44 rows=1 width=4)
   Index Cond: ((name)::text = 'a1234567'::text)

3、建立Query Mapping

像以上例子,可能修改SQL是不現實的,或是很麻煩的。有沒有能不修改SQL,並且能快速解決問題的方法?KINGBASE Query Mapping 就是為實現該功能而量身定做的優化技術。

#建立SQL對映關係
select create_query_rule('qm1','select id from v_t1 where name=$1;','select id from t1 where name=lower($1);', true, 'text');
select create_query_rule('qm2','select id from v_t1 where name=$1;','select id from t1 where name=lower($1);', true, 'semantics');
#刪除對映關係
select drop_query_rule('qm1'); 

在建立mapping時,有兩種模式:

  • text在語法詞法解析之前做的轉化,字串匹配,執行快。
  • semantics是轉化為查詢樹之後再做轉化,會進行語法檢查,區分不同schema。對於過程或者匿名塊內部的SQL,需要使用這種模式。優化器首先對匿名塊作詞法語法解析,然後執行的時候發現是查詢的查詢樹,會先進行替換,生成執行計劃。

可以檢視sys_query_mapping,確認系統建立了哪些query mapping。

4、Mapping後執行計劃

查詢檢視 v_t1 也可以使用到索引。

test=# explain (usingquerymapping, analyze) select id from v_t1 where name='A1234567';
                                                   QUERY PLAN                                                   
----------------------------------------------------------------------------------------------------------------
 Index Scan using ind_t1_name on t1  (cost=0.42..8.44 rows=1 width=4) (actual time=0.018..0.019 rows=1 loops=1)
   Index Cond: ((name)::text = 'a1234567'::text)
 Planning Time: 0.067 ms
 Execution Time: 0.035 ms
(4 rows)

注意紅色部分不能少。

再看下不使用(usingquerymapping, analyze)情況下的執行計劃:顯示的是對映前的執行計劃。

test=# explain  select id from v_t1 where name='A1234567';
                                         QUERY PLAN                                         
--------------------------------------------------------------------------------------------
 Seq Scan on t1  (cost=0.00..22906.00 rows=5000 width=4)
   Filter: (((upper((name)::text))::character varying(8000 char))::text = 'A1234567'::text)
(2 rows)

4、如何確認Query Mapping是否升效?

如何確認SQL :select id from v_t1 where name=$1 是否會進行轉換了?可以通過查詢sys_stat_statements 確認實際執行的SQL。

test=# select id from v_t1 where name='A1234567';     
   id   
--------
 234567
(1 row)

test=# select id from v_t1 where name='A1234567';
   id   
--------
 234567
(1 row)

test=# select id from v_t1 where name='A1234567';
   id   
--------
 234567
(1 row)

test=# select query,calls from sys_stat_statements where query like '%lower%';
                 query                  | calls 
----------------------------------------+-------
 select id from t1 where name=lower($1) |     3
(1 row)

可以看出SQL對映是生效的。

三、Query Mapping對於效能影響

Query Mapping 在生成執行計劃時,必須先讀取sys_query_mapping,不可避免對於效能有一定影響。以下的例子可以看到,query mapping 還是會有20%左右的效能影響。

test=# declare
test-#   v_temp integer;
test-#   v_val text;
test-# begin
test-#   for i in 1000001..2010000 loop
test-#     execute 'select id from t1 where name=$1' into v_temp using 'a'||i;
test-#   end loop;
test-# end;
test-# /
Time: 102585.759 ms (01:42.586)

test=# declare
test-#   v_temp integer;
test-#   v_val text;
test-# begin
test-#   for i in 1000001..2010000 loop
test-#     execute 'select id from v_t1 where name=$1' into v_temp using 'A'||i;
test-#   end loop;
test-# end;
test-# /
Time: 128438.435 ms (02:08.438)

四、使用注意

query mapping 要求大寫嚴格一致。

--表名 大小寫不一致,無法使用query mapping
test=# explain (usingquerymapping, analyze) select id from V_T1 where name='A1234567';
                                              QUERY PLAN                                              
------------------------------------------------------------------------------------------------------
 Seq Scan on t1  (cost=0.00..22906.00 rows=5000 width=4) (actual time=99.525..407.516 rows=1 loops=1)
   Filter: (((upper((name)::text))::character varying(8000 char))::text = 'A1234567'::text)
   Rows Removed by Filter: 999999
 Planning Time: 0.448 ms
 Execution Time: 407.542 ms
(5 rows)

--空格後面不一致,不影響 query mapping使用 test
=# explain (usingquerymapping, analyze) select id from v_t1 where name='A1234567'; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Scan using ind_t1_name on t1 (cost=0.42..8.44 rows=1 width=4) (actual time=0.022..0.022 rows=1 loops=1) Index Cond: ((name)::text = 'a1234567'::text) Planning Time: 0.062 ms Execution Time: 0.036 ms (4 rows)
--FROM 大小寫不一致,無法使用query mapping test
=# explain (usingquerymapping, analyze) select id From v_t1 where name='A1234567'; QUERY PLAN ------------------------------------------------------------------------------------------------------ Seq Scan on t1 (cost=0.00..22906.00 rows=5000 width=4) (actual time=98.008..417.077 rows=1 loops=1) Filter: (((upper((name)::text))::character varying(8000 char))::text = 'A1234567'::text) Rows Removed by Filter: 999999 Planning Time: 0.159 ms Execution Time: 417.097 ms (5 rows)