利用FORCE_MATCHING_SIGNATURE捕获非绑定变量SQL

做为一个DBA,你大概习惯了定期要抓取数据库中的非绑定变量SQL,这些SQL经常扮演着一箱苹果中蛀虫的角色。
看到下列SQL你必定觉得眼熟:

SELECT substr(sql_text, 1, 80), count(1)
  FROM v$sql
 GROUP BY substr(sql_text, 1, 80)
HAVING count(1) > 10
 ORDER BY 2

是的,以上这段抓取literal sql的脚本大约从8i时代就开始流行了,在那时它很popular也很休闲,使用它或许还会给你的雇主留下一丝神秘感。不过今天我要告诉你的是,它彻底过时了,落伍了,已经不是fashion master了。
10g以后v$SQL动态性能视图增加了FORCE_MATCHING_SIGNATURE列,其官方定义为”The signature used when the CURSOR_SHARING parameter is set to FORCE”,也就是Oracle通过将原SQL_TEXT转换为可能的FORCE模式后计算得到的一个SIGNATURE值。这么说可能不太形象,我们来具体看一下:

SQL> create table YOUYUS (t1 int);
Table created.

SQL> alter system flush shared_pool;
System altered.

SQL>select /*test_matching_a*/ * from YOUYUS where t1=1;
no rows selected

SQL>select /*test_matching_a*/ * from YOUYUS where t1=2;
no rows selected

SQL>select /*test_matching_a*/ * from YOUYUS where t1=3;
no rows selected

SQL> col sql_text format a55;
SQL> select sql_text, FORCE_MATCHING_SIGNATURE, EXACT_MATCHING_SIGNATURE
  2    FROM V$SQL
  3   WHERE sql_text like '%test_matching_a%'
  4     and sql_text not like '%like%';

SQL_TEXT                                                FORCE_MATCHING_SIGNATURE EXACT_MATCHING_SIGNATURE
------------------------------------------------------- ------------------------ ------------------------
select /*test_matching_a*/ * from YOUYUS where t1=2          4.59124694481197E18      1.00267830752731E19
select /*test_matching_a*/ * from YOUYUS where t1=3          4.59124694481197E18      1.61270448861426E19
select /*test_matching_a*/ * from YOUYUS where t1=1          4.59124694481197E18      1.36782048270058E18

/*以上将变量硬编码至SQL中的游标,FORCE_MATCHING_SIGNATURE值完全相同,而EXACT_MATCHING_SIGNATURE值各有不同。FORCE_MATCHING_SIGNATURE值相同说明在游标共享FORCE模式下,这些游标满足CURSOR SHARING的条件 */

SQL> alter system flush shared_pool;
System altered.
SQL> alter session set cursor_sharing=FORCE;
Session altered.

SQL>select /*test_matching_a*/ * from YOUYUS where t1=1;
no rows selected

SQL>select /*test_matching_a*/ * from YOUYUS where t1=2;
no rows selected

SQL>select /*test_matching_a*/ * from YOUYUS where t1=3;
no rows selected

SQL> col sql_text for a70
SQL> select sql_text, FORCE_MATCHING_SIGNATURE, EXACT_MATCHING_SIGNATURE
  2    FROM V$SQL
  3   WHERE sql_text like '%test_matching_a%'
  4     and sql_text not like '%like%';

SQL_TEXT                                                               FORCE_MATCHING_SIGNATURE EXACT_MATCHING_SIGNATURE
---------------------------------------------------------------------- ------------------------ ------------------------
select /*test_matching_a*/ * from YOUYUS where t1=:"SYS_B_0"                4.59124694481197E18      4.59124694481197E18

/*FORCE模式下将SQL文本中的变量值转换成了:SYS_B形式,EXACT_MATCHING_SIGNATURE也随之等同于FORCE_MATCHING_SIGNATURE了*/

以上演示说明了FORCE_MATCHING_SIGNATURE列可以帮助我们找出那些潜在可以共享的游标(也包括了因非绑定问题造成的游标无法共享),现在我们利用它来完善捕获非绑定变量SQL的脚本:

SQL> alter system flush shared_pool;
System altered.

SQL> select  /*test_matching_b*/ * from YOUYUS where t1=1;
no rows selected

SQL> select  /*test_matching_b*/ * from YOUYUS where t1='1';            //我有引号,我与众不同!
no rows selected

SQL> col sql_text for a70

SQL> select sql_text, FORCE_MATCHING_SIGNATURE, EXACT_MATCHING_SIGNATURE
  2    FROM V$SQL
  3   WHERE sql_text like '%test_matching_b%'
  4     and sql_text not like '%like%';

SQL_TEXT                                                               FORCE_MATCHING_SIGNATURE EXACT_MATCHING_SIGNATURE
---------------------------------------------------------------------- ------------------------ ------------------------
select  /*test_matching_b*/ * from YOUYUS where t1='1'                      1.43666633406896E19      1.83327833675856E19
select  /*test_matching_b*/ * from YOUYUS where t1=1                       1.43666633406896E19      8.05526057286178E18

/*多余的引号也会导致游标无法共享,此时的FORCE_MATCHING_SIGNATURE 也会是一致的*/

select FORCE_MATCHING_SIGNATURE, count(1)
  from v$sql
 where FORCE_MATCHING_SIGNATURE > 0
   and FORCE_MATCHING_SIGNATURE != EXACT_MATCHING_SIGNATURE
 group by FORCE_MATCHING_SIGNATURE
having count(1) > &a
 order by 2;

Enter value for a: 10
old   6: having count(1) > &a
new   6: having count(1) > 10

FORCE_MATCHING_SIGNATURE   COUNT(1)
------------------------ ----------
     8.81463386552502E18         12

So We find it!

在这里再推荐一种来自MOS,find Literal SQL的方法:

How to Find Literal SQL in Shared Pool


Applies to:

PL/SQL – Version: 8.1.7 to 10.2
Information in this document applies to any platform.

Goal

There is no direct way to query the dictionary for literal SQL only.

However the following example will try to exclude all SQL statements in the
shared pool that do use bind variables.

There still might be situations, with statements using subqueries, where the
example still will show SQL statements using bind variables.

Solution

Create the following PL/SQL block:

[maclean@rh2 bin]$ cat  find_literal.sql

set serveroutput on
set linesize 120
--
-- This anonymous PL/SQL block must be executed as INTERNAL or SYS
-- Execute from : SQL*PLUS
-- CAUTION:
-- This sample program has been tested on Oracle Server - Enterprise Edition
-- However, there is no guarantee of effectiveness because of the possibility
-- of error in transmitting or implementing it. It is meant to be used as a
-- template, and it may require modification.
--
declare
b_myadr VARCHAR2(20);
b_myadr1 VARCHAR2(20);
qstring VARCHAR2(100);
b_anybind NUMBER;

cursor my_statement is
select address from v$sql
group by address;

cursor getsqlcode is
select substr(sql_text,1,60)
from v$sql
where address = b_myadr;

cursor kglcur is
select kglhdadr from x$kglcursor
where kglhdpar = b_myadr
and kglhdpar != kglhdadr
and kglobt09 = 0;

cursor isthisliteral is
select kkscbndt
from x$kksbv
where kglhdadr = b_myadr1;

begin

dbms_output.enable(10000000);

open my_statement;
loop
Fetch my_statement into b_myadr;
open kglcur;
fetch kglcur into b_myadr1;
if kglcur%FOUND Then
open isthisliteral;
fetch isthisliteral into b_anybind;
if isthisliteral%NOTFOUND Then
open getsqlcode;
fetch getsqlcode into qstring;
dbms_output.put_line('Literal:'||qstring||' address: '||b_myadr);
close getsqlcode;
end if;
close isthisliteral;
end if;
close kglcur;
Exit When my_statement%NOTFOUND;
End loop;
close my_statement;
end;
/

/*尝试执行*/

SQL> @find_literal
Literal:select inst_id, java_size, round(java_size / basejava_size,  address: 00000000BC6E94E8
Literal:select reason_id, object_id, subobject_id, internal_instance address: 00000000BC5F1D60
Literal:select  DBID, NAME, CREATED, RESETLOGS_CHANGE#, RESETLOGS_TI address: 00000000BC6000B0
Literal:select di.inst_id,di.didbi,di.didbn,to_date(di.dicts,'MM/DD/ address: 00000000BC530DA8
Literal:      declare          vsn  varchar2(20);             begin  address: 00000000BC85A9F8
Literal:SELECT INCARNATION#, RESETLOGS_CHANGE#, RESETLOGS_TIME, PRIO address: 00000000BC829978
Literal:select pos#,intcol#,col#,spare1,bo#,spare2 from icol$ where  address: 00000000BCA84D00
Literal:select SYS_CONTEXT('USERENV', 'SERVER_HOST'), SYS_CONTEXT('U address: 00000000BC771BF0
Literal: select sql_text, FORCE_MATCHING_SIGNATURE, EXACT_MATCHING_S address: 00000000BC4673A8
Literal:select streams_pool_size_for_estimate s,           streams_p address: 00000000BCA58848
Literal:         select open_mode from v$database address: 00000000BC5DF2D0
Literal:select FORCE_MATCHING_SIGNATURE, count(1)   from v$sql  wher address: 00000000BCA91628
Literal:select inst_id, tablespace_name, segment_file, segment_block address: 00000000BC66EF38
Literal:select sum(used_blocks), ts.ts#   from GV$SORT_SEGMENT gv, t address: 00000000BCAA01B0
Literal:BEGIN DBMS_OUTPUT.ENABLE(NULL); END; address: 00000000BC61D2D8
Literal:select value$ from props$ where name = 'GLOBAL_DB_NAME' address: 00000000BC570500
Literal:select count(*) from sys.job$ where (next_date > sysdate) an address: 00000000BC6C53F8
Literal:select java_pool_size_for_estimate s,           java_pool_si address: 00000000BCA65070
Literal:select local_tran_id, global_tran_fmt, global_oracle_id, glo address: 00000000BC5900B8
Literal:select inst_id,kglnaobj,kglfnobj,kglobt03, kglobhs0+kglobhs1 address: 00000000BC921538
Literal:select o.owner#,o.name,o.namespace,o.remoteowner,o.linkname, address: 00000000BCA83E90
Literal:SELECT * FROM V$SQL address: 00000000BCA58BC0
Literal:SELECT ADDRESS FROM V$SQL GROUP BY ADDRESS address: 00000000BC565BE8
Literal:      begin          dbms_rcvman.resetAll;       end; address: 00000000BC759858
Literal:declare b_myadr VARCHAR2(20); b_myadr1 VARCHAR2(20); qstring address: 00000000BC928FF8
Literal:select /*+ rule */ bucket_cnt, row_cnt, cache_cnt, null_cnt, address: 00000000BC898BF8
Literal:select CONF#, NAME, VALUE from GV$RMAN_CONFIGURATION where i address: 00000000BC8CB7F8
Literal:select f.file#, f.block#, f.ts#, f.length from fet$ f, ts$ t address: 00000000BC8CDFE8
Literal:select u.name, o.name, trigger$.sys_evts, trigger$.type#  fr address: 00000000BCA877B8
Literal:select id, name, block_size, advice_status,                  address: 00000000BC636B38
Literal:select incarnation#, resetlogs_change#, resetlogs_time,      address: 00000000BCA94250
Literal:select  INSTANCE_NUMBER , INSTANCE_NAME , HOST_NAME , VERSIO address: 00000000BC62A678
Literal:select ks.inst_id,ksuxsins,ksuxssid,ksuxshst,ksuxsver,ksuxst address: 00000000BC8E5440
Literal:select timestamp, flags from fixed_obj$ where obj#=:1 address: 00000000BC916C78
Literal:select size_for_estimate,                      size_factor * address: 00000000BCA5F830
Literal:select shared_pool_size_for_estimate s,          shared_pool address: 00000000BCA5A350
Literal:select  SQL_TEXT , SQL_FULLTEXT , SQL_ID,  SHARABLE_MEM , PE address: 00000000BC76B3A0
Literal:lock table sys.col_usage$ in exclusive mode nowait address: 00000000BCA05978
Literal:select 'x' from dual  address: 00000000BC583818
Literal:      select name, resetlogs_time,              resetlogs_ch address: 00000000BCA9D430
Literal:select inst_id, sp_size, round(sp_size / basesp_size, 4),  k address: 00000000BC65A9F0
Literal:select userenv('Instance'),  icrid, to_number(icrls),        address: 00000000BC692260
Literal:select shared_pool_size_for_estimate, shared_pool_size_facto address: 00000000BCAE0750
Literal:select INST_ID, RMRNO, RMNAM, RMVAL from X$KCCRM where RMNAM address: 00000000BC8CD778
Literal:select metadata from kopm$  where name='DB_FDO' address: 00000000BC9EBB98
Literal:select java_pool_size_for_estimate, java_pool_size_factor,   address: 00000000BC5B27D0
Literal:SELECT INCARNATION#, INCARNATION#, RESETLOGS_CHANGE#, RESETL address: 00000000BC829C48
Literal:select file# from file$ where ts#=:1 address: 00000000BC87CF18
Literal:select A.inst_id, A.bpid, B.bp_name, A.blksz,                address: 00000000BC802248
Literal:lock table sys.mon_mods$ in exclusive mode nowait address: 00000000BC5CBE68
Literal:lock table sys.mon_mods$ in exclusive mode nowait address: 00000000BC5CBE68

关注dbDao.com的新浪微博

扫码关注dbDao.com 微信公众号:

Comments

  1. admin says:

    Hdr: 9959708 10.2.0.4.0 RDBMS 10.2.0.4.0 SVRMAN SQLTN PRODID-5 PORTID-226
    Abstract: V$SQL.EXACT_MATCHING_SIGNATURE IS 0 FOR INSERT SELECT
    PROBLEM:
    ——–
    V$SQL.EXACT_MATCHING_SIGNATURE IS 0 for an Insert Select preventing from
    matching successfully to a SQL Profile.

    DIAGNOSTIC ANALYSIS:
    ——————–
    SQL>INSERT INTO WRK_IDS_2_RDW_TXN_HELPER PARTITION(GPRO)
    2 SELECT –+ index(ids_account)
    3 ids_transaction.transaction_id,
    ….

    select exact_matching_signature,force_matching_signature
    from v$sql
    where sql_id=’gyfxnj0wzu5mn’;

    EXACT_MATCHING_SIGNATURE FORCE_MATCHING_SIGNATURE
    ———————— ————————
    0 0

    WORKAROUND:
    ———–
    None

    RELATED BUGS:
    ————-
    Bug 8249298 V$SQL.FORCE_MATCHING_SIGNATURE IS 0 FOR VALID SQL_IDS

    REPRODUCIBILITY:
    —————-
    reproduces in 10.2.0.4, 10.2.0.5
    Does not reproduces in 11.1.0.7

    TEST CASE:
    ———-
    Uploaded. Run setup.sql from / as sysdba . Needs existing USERS tablespace

    STACK TRACE:
    ————

    SUPPORTING INFORMATION:
    ———————–

    24 HOUR CONTACT INFORMATION FOR P1 BUGS:
    —————————————-

    DIAL-IN INFORMATION:
    ——————–

    IMPACT DATE:
    ————

  2. 还有 Tom的方法,, 呵呵 很安全。。 MOS的那种方法我曾经提供给客户,结果一运行 ,db hang了。。

    tkyte@TKYTE816> create or replace
    2 function remove_constants( p_query in varchar2 )
    3 return varchar2
    4 as
    5 l_query long;
    6 l_char varchar2(1);
    7 l_in_quotes boolean default FALSE;
    8 begin
    9 for i in 1 .. length( p_query )
    10 loop
    11 l_char := substr(p_query,i,1);
    12 if ( l_char = ʹʹʹʹ and l_in_quotes )
    13 then
    14 l_in_quotes := FALSE;
    15 elsif ( l_char = ʹʹʹʹ and NOT l_in_quotes )
    16 then
    17 l_in_quotes := TRUE;
    18 l_query := l_query || ʹʹʹ#ʹ;
    19 end if;
    20 if ( NOT l_in_quotes ) then
    21 l_query := l_query || l_char;
    22 end if;
    23 end loop;
    24 l_query := translate( l_query, ʹ0123456789ʹ, ʹ@@@@@@@@@@ʹ );
    25 for i in 0 .. 8 loop
    26 l_query := replace( l_query, lpad(ʹ@ʹ,10‐i,ʹ@ʹ), ʹ@ʹ );
    27 l_query := replace( l_query, lpad(ʹ ʹ,10‐i,ʹ ʹ), ʹ ʹ );
    28 end loop;
    29 return upper(l_query);
    30 end;
    31 /
    Function created.

    tkyte@TKYTE816> create global temporary table sql_area_tmp
    2 on commit preserve rows
    3 as
    4 select sql_text, sql_text sql_text_wo_constants
    5 from v$sqlarea
    6 where 1=0
    7 /
    Table created.

    tkyte@TKYTE816> insert into sql_area_tmp (sql_text)
    2 select sql_text from v$sqlarea
    3 /

    tkyte@TKYTE816> update sql_area_tmp
    2 set sql_text_wo_constants = remove_constants(sql_text);
    3 /
    436 rows updated.

    tkyte@TKYTE816> select sql_text_wo_constants, count(*)
    2 from sql_area_tmp
    3 group by sql_text_wo_constants
    4 having count(*) > 10
    5 order by 2
    6 /
    SQL_TEXT_WO_CONSTANTS COUNT(*)
    ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ‐‐‐‐‐‐‐‐‐‐
    INSERT INTO T VALUES ( @) 100

  3. maclean says:
    WITH rc AS
     (SELECT force_matching_signature_key,
             TYPE,
             status,
             namespace,
             force_matching_signature,
             depend_key,
             sql_text,
             num_results,
             block_count,
             row_count,
             build_time,
             scan_count,
             saved_time,
             executions,
             buffer_gets,
             elapsed_time,
             depend_name,
             depend_type,
             depend_status,
             saved_buffer_gets,
             hit_ratio,
             time_saved_ratio
        FROM (SELECT force_matching_signature_key,
                     TYPE,
                     status,
                     namespace,
                     force_matching_signature,
                     depend_key,
                     sql_text,
                     num_results,
                     block_count,
                     row_count,
                     build_time,
                     scan_count,
                     saved_time,
                     executions,
                     buffer_gets,
                     elapsed_time,
                     depend_name,
                     depend_type,
                     depend_status,
                     CASE
                       WHEN (executions - scan_count) < = 0 THEN
                        0
                       ELSE
                        scan_count * (buffer_gets / (executions - scan_count))
                     END saved_buffer_gets,
                     CASE
                       WHEN executions = 0 THEN
                        0
                       ELSE
                        100 * scan_count / executions
                     END hit_ratio,
                     CASE
                       WHEN elapsed_time = 0 THEN
                        0
                       ELSE
                        100 * saved_time / elapsed_time
                     END time_saved_ratio
                FROM (SELECT rc.TYPE || '_' || rc.status || '_' || rc.namespace || '_' || CASE
                               WHEN rc.namespace = 'SQL' THEN
                                NVL(TO_CHAR(s.force_matching_signature), rc.name)
                               ELSE
                                rc.name
                             END force_matching_signature_key,
                             rc.TYPE,
                             rc.status,
                             rc.namespace,
                             TO_CHAR(s.force_matching_signature) force_matching_signature,
                             rc.depend_type || '_' || rc.depend_id depend_key,
                             CASE
                               WHEN rc.namespace = 'SQL' THEN
                                NVL(MAX(s.sql_text), MAX(rc.name))
                               ELSE
                                MAX(rc.name)
                             END sql_text,
                             SUM(rc.num_results) num_results,
                             SUM(rc.block_count) block_count,
                             SUM(rc.row_count) row_count,
                             SUM(rc.build_time) * 10 build_time,
                             SUM(rc.scan_count) scan_count,
                             SUM(rc.saved_time) * 10 saved_time,
                             NVL(SUM(s.executions), 0) executions,
                             NVL(SUM(s.buffer_gets), 0) buffer_gets,
                             NVL(SUM(s.elapsed_time / 1000), 0) elapsed_time,
                             rc.depend_name,
                             rc.depend_type,
                             rc.depend_status
                        FROM (SELECT sp.sql_id,
                                     rco.TYPE,
                                     rco.status,
                                     rco.namespace,
                                     rco.name,
                                     rco.depend_id,
                                     rco.depend_name,
                                     rco.depend_type,
                                     rco.depend_status,
                                     rco.block_count,
                                     rco.row_count,
                                     rco.build_time,
                                     rco.scan_count,
                                     rco.saved_time,
                                     rco.num_results
                                FROM (SELECT /*+ ordered */
                                       rco.cache_id,
                                       rco.TYPE,
                                       rco.status,
                                       rco.namespace,
                                       rco.name,
                                       rcd.depend_id,
                                       rcod.name depend_name,
                                       rcod.TYPE depend_type,
                                       rcod.status depend_status,
                                       SUM(rco.block_count) block_count,
                                       SUM(rco.row_count) row_count,
                                       SUM(rco.build_time) build_time,
                                       SUM(rco.scan_count) scan_count,
                                       SUM(rco.scan_count * rco.build_time) saved_time,
                                       COUNT(*) num_results
                                        FROM v$result_cache_objects    rco,
                                             v$result_cache_dependency rcd,
                                             v$result_cache_objects    rcod
                                       WHERE rco.TYPE = 'Result'
                                         AND rcd.result_id = rco.id
                                         AND rcod.id = rcd.depend_id                                  
                                       GROUP BY rco.cache_id,
                                                rco.TYPE,
                                                rco.status,
                                                rco.namespace,
                                                rco.name,
                                                rcd.depend_id,
                                                rcod.name,
                                                rcod.TYPE,
                                                rcod.status) rco,
                                     v$sql_plan sp
                               WHERE sp.operation(+) = 'RESULT CACHE'
                                 AND sp.object_name(+) = rco.cache_id
                               GROUP BY sp.sql_id,
                                        rco.TYPE,
                                        rco.status,
                                        rco.namespace,
                                        rco.name,
                                        rco.depend_id,
                                        rco.depend_name,
                                        rco.depend_type,
                                        rco.depend_status,
                                        rco.block_count,
                                        rco.row_count,
                                        rco.build_time,
                                        rco.scan_count,
                                        rco.saved_time,
                                        rco.num_results) rc,
                             v$sqlarea s
                       WHERE s.sql_id(+) = rc.sql_id
                       GROUP BY rc.TYPE,
                                rc.status,
                                s.force_matching_signature,
                                rc.namespace,
                                CASE
                                  WHEN rc.namespace = 'SQL' THEN
                                   NVL(TO_CHAR(s.force_matching_signature), rc.name)
                                  ELSE
                                   rc.name
                                END,
                                rc.depend_id,
                                rc.depend_name,
                                rc.depend_type,
                                rc.depend_status))
       WHERE ROWNUM <= 100)
    SELECT force_matching_signature_key, TYPE, status, namespace, force_matching_signature, depend_key, sql_text, num_results, block_count, row_count, build_time, scan_count, saved_time, executions, buffer_gets, elapsed_time, saved_buffer_gets, hit_ratio, time_saved_ratio
      FROM rc
    UNION ALL
    SELECT rc.depend_key force_matching_signature_key, rc.depend_TYPE, rc.depend_status, NULL namespace, NULL force_matching_signature, NULL depend_key, rc.depend_name sql_text, NULL num_results, NULL block_count, NULL row_count, NULL build_time, NULL scan_count, NULL saved_time, NULL executions, NULL buffer_gets, NULL elapsed_time, NULL saved_buffer_gets, NULL hit_ratio, NULL time_saved_ratio
      FROM rc
     GROUP BY rc.depend_key, rc.depend_TYPE, rc.depend_status, rc.depend_name 
     /
    
  4. bobjoy says:

    测试了一下,确实是oracle认为还未利用绑定变量的sql语句这两个值就不同。
    这个方法,简单实用。
    厉害,thanks。

  5. select sql_id, FORCE_MATCHING_SIGNATURE, sql_text from v$SQL where FORCE_MATCHING_SIGNATURE in (select /*+ unnest */ FORCE_MATCHING_SIGNATURE from v$sql where FORCE_MATCHING_SIGNATURE > 0 and FORCE_MATCHING_SIGNATURE != EXACT_MATCHING_SIGNATURE group by FORCE_MATCHING_SIGNATURE having count(1) > 10)

  6. snowdrop says:

    Xin提供的方法和刘大的方法测试出来的数据不一样啊,Xin提供的方法测试数据是空的,解释下原因?

  7. snowdrop says:

    就是二楼提供的tom的那个方法,测试的数据是空的

Trackbacks

  1. […] 参考连接:http://www.askmaclean.com/archives/%E5%88%A9%E7%94%A8force_matching_signature%E6%8D%95%E8%8E%B7%E9%9… […]

  2. […] 参考连接:http://www.askmaclean.com/archives/%E5%88%A9%E7%94%A8force_matching_signature%E6%8D%95%E8%8E%B7%E9%9… […]

Speak Your Mind

TEL/電話+86 13764045638
Email service@parnassusdata.com
QQ 47079569