?分布式查询语句对于远程对象的查询在远程库执行,在远程可以执行的语句会通过优化器的查询转换,执行的是转换后的语句,然后结果集返回到本地,再与本地表运算。当然, 本地还是远程是相对的,我们可以通过driving_hint改变主查询计划的执行位置,但是对DML
?分布式查询语句对于远程对象的查询在远程库执行,在远程可以执行的语句会通过优化器的查询转换,执行的是转换后的语句,然后结果集返回到本地,再与本地表运算。当然,
本地还是远程是相对的,我们可以通过driving_hint改变主查询计划的执行位置,但是对DML,driving_site是失效的。另外对远程表也可以使用其他hint。
???分布式查询可能一条SQL语句中有不同远程库的表,优化分布式查询要达到3点效果:
1.访问同一个远程库的次数要尽量少,也就是同一远程库的对象应该尽量转为一条SQL运算,一次运算,运算后将结果返回给本地库
2.从远程库上返回到本地库的结果要尽量少,只访问远程对象需要的字段
3.远程库上执行的语句的计划以及远程库返回的结果与本地可以联合查询的计划应该高效
?优化分布式查询需要从以上3个方面着手。
下面的local_tab 7万多条,remote_big_tab百万条,remote_small_tab 7万多条。
?1.使用Collocated内联视图
? 也就是SQL要对引用不同远程库的表,要组织好,将相同库的表放一起组织成内联视图,这样ORACLE就很容易知道这个内联视图里的表是在同一远程库作完查询
? 后再返回给本地库,这样减少了本地库与远程库的交互次数和传输结果集的数量和次数。比如上面的查询
SELECT ?* FROM local_tab a ?WHERE EXISTS ?(SELECT ?1 FROM remote_big_tab@remote b,remote_small_tab@remote c ?WHERE b.object_id=c.object_id AND a.object_type=b.object_type); 执行计划 |
? 可以看出,在远程库remote上执行的语句是两个远程表关联后,并经过查询转换(全转为大写,自己取了别名A1,A2,ORACLE内部自己改造为止查询DISTINCT ??remote_big_tab.object_type),之后远程查询结果返回给本地,可以去远程库里查询实际的计划,走的是HASH JOIN。
2.了解CBO优化器对分布式查询的处理
? ?CBO对分布式查询的处理,也是尽量转为Collocated内联视图,CBO会做如下动作:
? ?1)所有可mergeable的视图会merge
? ?2 ) CBO会测试Collocated内联视图的query BLOCK
? ?3 ) 如果可以使用,就使用合并
? ?当然,CBO对分布式查询的处理,可能是不高效的,这时候得用其他的方法,比如使用HINT,改造SQL,改造分布式查询的方法(远程库用视图)等。
???特别当分布式查询包含下列情况,CBO可能是不高效的:
? ?1)有分组运算
? ?2)有子查询
? ?3)SQL很复杂
? ?
? ?比如下面语句含有子查询:
SELECT ?* FROM local_tab a,remote_big_tab@remote b,remote_small_tab@remote c ?WHERE b.object_id=c.object_id AND a.object_type=b.object_type ?AND a.object_id IN (SELECT object_id from sub); 执行计划 ———————————————————- Plan hash value: 252158753 ———————————————————————————————————- | Id ?| Operation ? ? ? ? ? ? | Name ? ? ? ? ? ? | Rows ?| Bytes | Cost (%CPU)| Time ? ? | Inst ? |IN-OUT| ———————————————————————————————————- | ? 0 | SELECT STATEMENT ? ? ?| ? ? ? ? ? ? ? ? ?| ? ?79M| ? ?20G| ?3843 ?(46)| 00:00:47 | ? ? ? ?| ? | |* ?1 | ?HASH JOIN ? ? ? ? ? ?| ? ? ? ? ? ? ? ? ?| ? ?79M| ? ?20G| ?3843 ?(46)| 00:00:47 | ? ? ? ?| ? | | ? 2 | ??REMOTE ? ? ? ? ? ? ?| REMOTE_SMALL_TAB?| ?5320 | ? 431K| ? ? 8 ? (0)| 00:00:01 | REMOTE | R->S | |* ?3 | ? HASH JOIN ? ? ? ? ? | ? ? ? ? ? ? ? ? ?| ? 172M| ? ?31G| ?2978 ?(31)| 00:00:36 | ? ? ? ?| ? | |* ?4 | ? ?HASH JOIN ? ? ? ? ?| ? ? ? ? ? ? ? ? ?| ?5260 | ? 565K| ? 303 ? (2)| 00:00:04 | ? ? ? ?| ? | | ? 5 | ? ? SORT UNIQUE ? ? ? | ? ? ? ? ? ? ? ? ?| ?5320 | 69160 | ? ? 5 ? (0)| 00:00:01 | ? ? ? ?| ? | | ? 6 | ? ? ?TABLE ACCESS FULL| SUB ? ? ? ? ? ? ?| ?5320 | 69160 | ? ? 5 ? (0)| 00:00:01 | ? ? ? ?| ? | | ? 7 | ? ? TABLE ACCESS FULL | LOCAL_TAB ? ? ? ?| 73985 | ?7008K| ? 296 ? (1)| 00:00:04 | ? ? ? ?| ? | | ? 8 | ???REMOTE ? ? ? ? ? ? | REMOTE_BIG_TAB?? | ?1479K| ? 119M| ?1819 ? (2)| 00:00:22 | REMOTE | R->S | ———————————————————————————————————- Predicate Information (identified by operation id): ————————————————— ? ?1 – access(“B”.”OBJECT_ID”=”C”.”OBJECT_ID”) ? ?3 – access(“A”.”OBJECT_TYPE”=”B”.”OBJECT_TYPE”) ? ?4 – access(“A”.”OBJECT_ID”=”OBJECT_ID”) Remote SQL Information (identified by operation id): ???2 – SELECT “OBJECT_NAME”,”SUBOBJECT_NAME”,”OBJECT_ID”,”DATA_OBJECT_ID”,”OBJECT_TYPE”,”CREATED”, ? ?8 – SELECT “OWNER”,”OBJECT_NAME”,”SUBOBJECT_NAME”,”OBJECT_ID”,”DATA_OBJECT_ID”,”OBJECT_TYPE”,”C ? |
?通过计划可以看到REMOTE有两个,两张远程表无法做Collocated inline VIEW运算。
?
? 再比如下面的语句,有分组运算:
SELECT ?* FROM local_tab a,remote_big_tab@remote b,(SELECT max(object_id) object_id FROM remote_small_tab@remote c GROUP BY c.object_type) c WHERE b.object_id=c.object_id AND a.object_type=b.object_type; 执行计划 Remote SQL Information (identified by operation id): |
?? 通过计划看出,将远程表进行分组运算后,传输给本地库,然后大表传输给本地库,之后做HASH JOIN,这是不高效的。运行时间:已用时间: ?00: 02: 12.22
?可以改造分布式查询,手动组织Collocated inline VIEW,在远程库建立view:
CREATE OR REPLACE VIEW v_remote AS SELECT ?b.* FROM remote_big_tab b,(SELECT max(object_id) object_id FROM remote_small_tab c GROUP BY c.object_type) c WHERE b.object_id=c.object_id;? 查询改为: 执行计划 |
?通过计划可以看出,现在是远程表做整体操作之后才返回到本地了。
?3.使用HINT,特别是driving_site HINT
? 对远程表可以使用hint,比如parallel,use_nl,use_hash,FULL等。
? driving_site hint能够指定执行计划在远程还是本地做,比如下面使用driving_site(b),那么原来的远程表就相当于本地表,本地表要传输给remote库,主计划在remote库上执行
??
SELECT/*+driving_site(b)*/ ?* FROM local_tab a,remote_big_tab@remote b,(SELECT max(object_id) object_id FROM remote_small_tab@remote c GROUP BY c.object_type) c WHERE b.object_id=c.object_id AND a.object_type=b.object_type; |
? ?当然,如果是driving_site(a)那么就是本地驱动的,默认的是本地驱动的。
? ?
? ?使用driving_site,特别是本地小结果集,远程大结果集的时候,总体结果集较小,希望计划在远程驱动,这样远程执行完毕,将结果集传输到本地,这样避免大结果集的传输。
? ?
? ?例1:
?? ? ? ??小表9998条,大表3169376条记录,远程大表sub_id,acc_id上联合索引
SQL> ?SELECT ?COUNT(*) ?FROM small_tab_local a, big_tab_remote@remote b ? 2 ? WHERE a.sub_id=b.sub_id AND a.acc_id=b.acc_id; ? ??? ? ?859 已用时间: ?00: 00: 50.76 执行计划 Predicate Information (identified by operation id): Remote SQL Information (identified by operation id): ? ?3 – SELECT “SUB_ID”,”ACC_ID” FROM “BIG_TAB_REMOTE” “B” ORDER BY “SUB_ID”,”ACC_ID” |
? ? 查询876条数据,耗时50s,显然将大结果集拉到本地做运算是不好的,因为本地表很小,远程大表有索引,如果能在远端执行,并走nl,那么显然效率非常好。使用driving_site hint改造查询如下:
??
SELECT/*+driving_site(b) ?ordered use_nl(b)*/ ?COUNT(*) FROM small_tab_local a, big_tab_remote@remote b ?WHERE a.sub_id=b.sub_id AND a.acc_id=b.acc_id; 计划如下: Predicate Information (identified by operation id): Remote SQL Information (identified by operation id): |
? ? ?现在主计划是在远端remote上执行的,本地表small_tab_local变成了远程表,会讲small_tab_local结果集送到远端,只查询了sub_id,acc_id,然后作为驱动表,与远端表做nl运算,
计划里可以看到远端表走索引了,最后将远端结果返回到本地。(事实上这里的远端库与本地库换了)
? driving_site hint注意点:
??driving_site对dml无效,dml以目标表所在库驱动SQL计划。比如下面的driving_site失效,后面的hint还是有效的。
? ?
? CREATE TABLE test_cnt (cnt NUMBER); ? INSERT INTO test_cnt ? SELECT/*+driving_site(b) ordered use_nl(b)*/ ?COUNT(*) FROM small_tab_local a, big_tab_remote@remote b ? WHERE a.sub_id=b.sub_id AND a.acc_id=b.acc_id; 已用时间:??00: 01: 31.48 执行计划 Remote SQL Information (identified by operation id): ? ?5 – SELECT?/*+ OPAQUE_TRANSFORM USE_NL (“B”) */?”SUB_ID”,”ACC_ID” FROM “BIG_TAB_REMOTE” “B” |
? 语句执行1分31s,driving_site hint失效,但是后面的NL没有失效,可以从计划中看出类似绑定变量的东西,这实际对于每个small_tab_local的结果集的行,将sub_id,acc_id传给远端表big_tab_remote,也就是:1,:2,这样本地的表筛选出多少行,远程语句?SELECT?/*+ OPAQUE_TRANSFORM USE_NL (“B”) */?”SUB_ID”,”ACC_ID” FROM “BIG_TAB_REMOTE” “B”
?WHERE?:1=”SUB_ID” AND :2=”ACC_ID” 就执行多少次。
?这里本地表9998条,无过滤条件,因此远程表语句运行了9998次,虽然远程查询也是走索引的,但是SQL被执行了9998次,是非常影响性能的。可以去远程库查询下:
?
SQL> SELECT sql_text,executions FROM v$sql WHERE sql_text LIKE ‘%SELECT /*+ USE_NL (“B”) */ “SUB_ID”,”ACC_ID” FROM “BIG_TAB_REMOTE”%’ ? 2 ?/ ? SQL_TEXT ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? EXECUTIONS ——————————————————————————– ————————————————————– SELECT /*+ USE_NL (“B”) */ “SUB_ID”,”ACC_ID” FROM “BIG_TAB_REMOTE” “B” WHERE :1= ? ??? 9998 |
? ?这里driving_site失效,但是后面的nl还有效,远程表执行的次数是small_tab_local表的数量(因为这里没有谓词过滤small_tab_local),可以使用其他hint,比如。
? INSERT INTO test_cnt
? SELECT/*+ordered use_hash(b)*/ ? COUNT(*) FROM small_tab_local a, big_tab_remote@remote b
? WHERE a.sub_id=b.sub_id AND a.acc_id=b.acc_id;
??
??当然效率不一定很好,因为这里由远程驱动效率最好,为了不想driving_site失效,可以使用PL/SQL(这里是只查询数量,如果查询结果集可以使用PL/SQL批处理插入)。
BEGIN ? ? FOR i IN (SELECT/*+driving_site(b) ordered use_nl(b)*/ ?COUNT(*) cnt FROM small_tab_local a, big_tab_remote@remote b ? ? ? ? ? ? ? ? ? ?WHERE a.sub_id=b.sub_id AND a.acc_id=b.acc_id) ? ?LOOP ? ? ?INSERT INTO test_cnt VALUES(i.cnt); ? END LOOP; ? COMMIT; END; 已用时间:??00: 00: 00.89 |
? ? ?
? 例2:
? ? ? 查询语句:
SELECT * FROM?v_remote?WHERE object_id IN ( ??SELECT c.object_id FROM c WHERE c.object_name ? ? ? ? ?? IN (SELECT d.object_name FROM d WHERE d.object_id=11) ); |
?比较慢,返回32行,需要10来秒。其中v_remote是个视图,此视图连接到远程表,其中远程的两张表的object_id都有索引:
CREATE OR REPLACE VIEW v_remote AS SELECT object_name,object_id,object_type FROM a@remote ? UNION ALL SELECT ?object_name,object_id,object_type FROM b@remote; 两表记录数如下: |
? c和d是本地表,d.object_id以及c.object_name有索引。单独查询很快,
–单独本地语句消耗时间00: 00: 00.01 SQL> SELECT c.object_id FROM c WHERE c.object_name IN (SELECT d.object_name FROM d WHERE d.object_id=11); 已用时间: ?00: 00: 00.01 执行计划 ———————————————————- Plan hash value: 2528799293 —————————————————————————————- | Id ?| Operation ? ? ? ? ? ? ? ? ? ? ?| Name ?| Rows ?| Bytes | Cost (%CPU)| Time ? ? | —————————————————————————————- | ? 0 | SELECT STATEMENT ? ? ? ? ? ? ? | ? ? ? | ? ? 2 | ? ?94 | ? ? 6 ?(17)| 00:00:01 | | ? 1 | ?NESTED LOOPS ? ? ? ? ? ? ? ? ?| ? ? ? | ? ? ? | ? ? ? | ? ? ? ? ? ?| ? ? ? ? ?| | ? 2 | ? NESTED LOOPS ? ? ? ? ? ? ? ? | ? ? ? | ? ? 2 | ? ?94 | ? ? 6 ?(17)| 00:00:01 | | ? 3 | ? ?SORT UNIQUE ? ? ? ? ? ? ? ? | ? ? ? | ? ? 1 | ? ?17 | ? ? 2 ? (0)| 00:00:01 | | ? 4 | ? ? TABLE ACCESS BY INDEX ROWID| D ? ? | ? ? 1 | ? ?17 | ? ? 2 ? (0)| 00:00:01 | |* ?5 | ? ? ?INDEX RANGE SCAN ? ? ? ? ?| IDX_D | ? ? 1 | ? ? ? | ? ? 1 ? (0)| 00:00:01 | |* ?6 | ? ?INDEX RANGE SCAN ? ? ? ? ? ?| IDX_C | ? ? 2 | ? ? ? | ? ? 2 ? (0)| 00:00:01 | | ? 7 | ? TABLE ACCESS BY INDEX ROWID ?| C ? ? | ? ? 2 | ? ?60 | ? ? 3 ? (0)| 00:00:01 | —————————————————————————————- Predicate Information (identified by operation id): ————————————————— ? ?5 – access(“D”.”OBJECT_ID”=11) ? ?6 – access(“C”.”OBJECT_NAME”=”D”.”OBJECT_NAME”) –单独远程语句消耗时间?00: 00: 00.06 Remote SQL Information (identified by operation id): Predicate Information (identified by operation id): Remote SQL Information (identified by operation id): ? |
? ? ?单独查询很快,为什么联合查询就慢了呢?原因在于:
?
单独执行远程查询 | 本地与远程混合查询 |
直接执行视图,并将OBJECT_ID=11谓词推入到视图中,走索引,最后只将32行结果返回给本地 | 从计划中可以看到,本地查询与远程查询做HASH JOIN,但是访问远程的SQL是没有谓词的,这样必然全表从远程拉到本地,因为行数较多,所以慢 |
?
? ??因此,优化此混合查询的语句可以由多种办法(比如本地查询的数量较少,可以采用上面的方法,本地与远程查询拆分为2条语句),另外就是可以使用driving_site hint,将主计划推到远程库去执行,本地的结果集少,推到远程,远程视图走索引,效率高。如下:
–耗时已用时间: ?00: 00: 00.08 SQL> SELECT/*+driving_site(v_remote.a)*/ * FROM v_remote WHERE object_id IN ( ? 2 ?SELECT c.object_id FROM c WHERE c.object_name IN (SELECT d.object_name FROM d WHERE d.object_id=11 ? 3 ?); 已选择32行。 已用时间: ?00: 00: 00.08 ————————————————————————————— | Id ?| Operation ? ? ? ? ? ? ? ? ?| Name ? ? | Rows ?| Bytes | Cost ?| Inst ? |IN-OUT| ————————————————————————————— | ? 0 | SELECT STATEMENT REMOTE ? ?| ? ? ? ? ?| ? ?15 | ?1425 | ? 109 | ? ? ? ?| ? ? ?| | ? 1 | NESTED LOOPS ? ? ? ? ? ? ? | ? ? ? ? ?| ? ?15 | ?1425 | ? 109 | ? ? ? ?| ? ? ?| | ? 2 | SORT UNIQUE ? ? ? ? ? ? ? ?| ? ? ? ? ?| ? ? ? | ? ? ? | ? ? ? | ? ? ? ?| ? ? ?| | ? 3 | VIEW ? ? ? ? ? ? ? ? ? ? ? | VW_NSO_1 | ? ? 3 | ? ?39 | ? ? 8 | MZT~ | ? ? ?| | ? 4 |?REMOTE ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ?| ? ? ? | ? ? ? | ? ? ? | ? ? ?! | R->S?| | ? 5 | VIEW ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ?| ? ? 5 | ? 410 | ? ?33 | ? ? ? ?| ? ? ?| | ? 6 |?UNION-ALL PARTITION ? ? ? ?| ? ? ? ? ?| ? ? ? | ? ? ? | ? ? ? | ? ? ? ?| ? ? ?| | ? 7 | TABLE ACCESS BY INDEX ROWID| A ? ? ? ?| ? ?32 | ? 960 | ? ?35 |MZT~ | ? ? ?| |* ?8 | INDEX RANGE SCAN ? ? ? ? ? | IDX_A ? ?| ? ?32 | ? ? ? | ? ? 3 |MZT~ | ? ? ?| | ? 9 | TABLE ACCESS BY INDEX ROWID| B ? ? ? ?| ? ? 1 | ? ?32 | ? ? 2 | MZT~ | ? ? ?| |* 10 | INDEX RANGE SCAN ? ? ? ? ? | IDX_B ? ?| ? ? 1 | ? ? ? | ? ? 1 | MZT~ | ? ? ?| ————————————————————————————— Predicate Information (identified by operation id): Remote SQL Information (identified by operation id): |

MySQL索引基数对查询性能有显着影响:1.高基数索引能更有效地缩小数据范围,提高查询效率;2.低基数索引可能导致全表扫描,降低查询性能;3.在联合索引中,应将高基数列放在前面以优化查询。

MySQL学习路径包括基础知识、核心概念、使用示例和优化技巧。1)了解表、行、列、SQL查询等基础概念。2)学习MySQL的定义、工作原理和优势。3)掌握基本CRUD操作和高级用法,如索引和存储过程。4)熟悉常见错误调试和性能优化建议,如合理使用索引和优化查询。通过这些步骤,你将全面掌握MySQL的使用和优化。

MySQL在现实世界的应用包括基础数据库设计和复杂查询优化。1)基本用法:用于存储和管理用户数据,如插入、查询、更新和删除用户信息。2)高级用法:处理复杂业务逻辑,如电子商务平台的订单和库存管理。3)性能优化:通过合理使用索引、分区表和查询缓存来提升性能。

MySQL中的SQL命令可以分为DDL、DML、DQL、DCL等类别,用于创建、修改、删除数据库和表,插入、更新、删除数据,以及执行复杂的查询操作。1.基本用法包括CREATETABLE创建表、INSERTINTO插入数据和SELECT查询数据。2.高级用法涉及JOIN进行表联接、子查询和GROUPBY进行数据聚合。3.常见错误如语法错误、数据类型不匹配和权限问题可以通过语法检查、数据类型转换和权限管理来调试。4.性能优化建议包括使用索引、避免全表扫描、优化JOIN操作和使用事务来保证数据一致性

InnoDB通过undolog实现原子性,通过锁机制和MVCC实现一致性和隔离性,通过redolog实现持久性。1)原子性:使用undolog记录原始数据,确保事务可回滚。2)一致性:通过行级锁和MVCC确保数据一致。3)隔离性:支持多种隔离级别,默认使用REPEATABLEREAD。4)持久性:使用redolog记录修改,确保数据持久保存。

MySQL在数据库和编程中的地位非常重要,它是一个开源的关系型数据库管理系统,广泛应用于各种应用场景。1)MySQL提供高效的数据存储、组织和检索功能,支持Web、移动和企业级系统。2)它使用客户端-服务器架构,支持多种存储引擎和索引优化。3)基本用法包括创建表和插入数据,高级用法涉及多表JOIN和复杂查询。4)常见问题如SQL语法错误和性能问题可以通过EXPLAIN命令和慢查询日志调试。5)性能优化方法包括合理使用索引、优化查询和使用缓存,最佳实践包括使用事务和PreparedStatemen

MySQL适合小型和大型企业。1)小型企业可使用MySQL进行基本数据管理,如存储客户信息。2)大型企业可利用MySQL处理海量数据和复杂业务逻辑,优化查询性能和事务处理。

InnoDB通过Next-KeyLocking机制有效防止幻读。1)Next-KeyLocking结合行锁和间隙锁,锁定记录及其间隙,防止新记录插入。2)在实际应用中,通过优化查询和调整隔离级别,可以减少锁竞争,提高并发性能。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

WebStorm Mac版
好用的JavaScript开发工具

记事本++7.3.1
好用且免费的代码编辑器

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。