oracle 表连接 - hash join 哈希连接
一. hash 连接(哈希连接)原理
指的是两个表连接时, 先利用两表中记录较少的表在内存中建立 hash 表, 然后扫描记录较多的表并探測 hash 表, 找出与 hash 表相匹配的行来得到结果集的表连接方法. 哈希连接仅仅能用于等值连接条件(=)。
如果以下的 sql 语句中表 T1 和 T2 的连接方式是哈希连接, T1 是驱动表
select *
from T1, T2
where T1.id = T2.id and T1.name = 'David';
oracle 运行过程例如以下:
1 计算 hash partition 的数量 (分区数量)
这个数字由 hash_area_size, db_block_size, _hash_multiblock_io_count 的值来决定
hash partition 是一个逻辑上的概念, 它由多个 hash bucket 组成, 而一个 hash table 又由多个 hash partition 组成. hash partition 是 I/O 单位, 当 hash table 过大时, 以 hash partition 为单位写出到磁盘; hash bucket 是 hash 运算映射的单位, 能够把
hash bucket 想象为一个链表.
2 构建驱动结果集 S 的 hash table
2.1 遍历驱动结果集, 计算 hash 值
依据谓词条件(T1.name = 'David') 过滤驱动表 T1 的数据, 得到驱动结果集 S. 读取 S 中的每一条数据, 并依据连接列(T1.id)做 hash 运算.
oracle 採用两种 hash 算法进行计算, S 中的每一条记录都会得到两个哈希值记为 hash_value_1, hash_value_2.
2.2 存储数据到 hash partition
oracle 依照 hash_value_1 的值把驱动结果集 S 的记录映射存储在不同的 hash partition 中不同 hash bucket 里, 存储在 hash bucket 中的内容包含 sql 中的查询列, 连接列以及 hash_value_2 的值.
我们把驱动结果集 S 所相应的每个 hash partition 记为 S[i].
2.3 构建位图
这个位图用来标记 S[i] 所包括的每个 hash bucket 是否有记录
2.4 假设驱动结果集 S 数据量非常大, 则将数据交换到磁盘上(temp 表空间)
假设驱动结果集 S 的数据量非常大, 构建 S 相应的 hash table 时就会造成 PGA中的 hash_area_szie 被填满, 这时候 oracle 会把 hash area 中记录数最多的 hash partition 写到磁盘上. 反复步骤 2.1 - 2.4 直至读取数据完成.
另外, 在构建 S 相应的 hash table 时, 假设记录相应的 hash partition 已经被写到磁盘上, oracle 就会将 sql 中的查询列, 连接列以及hash_value_2 的值写到已经位于磁盘上的 hash partition 中不同 hash bucket 里.
2.5 排序
对驱动结果集 S 的 hash partition 依据记录数多少进行排序
3 遍历被驱动结果集 B
3.1 遍历驱动结果集 B 及位图过滤
把被驱动结果集 (T2) 记为 B, 读取 B 中的每一条记录, 并依照连接列(T2.id)做 hash 运算, 同步骤 (2) 一样得到两个哈希值 hash_value_1, hash_value_2. oracle 依据这个 hash_value_1 去 S[i] 匹配 hash bucket,
- 假设可以找到匹配的 bucket, 则进一步比較连接列是否相等, 假设相等, 则将记录 join 后返回; 假设不相等, 则舍弃;
- 假设找不到匹配的 bucket, 就会去訪问 2.3 中构建的位图,
假设位图显示该 hash bucket 在 S[i] 中相应的记录数大于 0, 则说明该 hash bucket 尽管不在内存中, 但实际上是被写到了磁盘上, 此时 oracle 会依照 hash_value_1 的值把被驱动结果集 B 的记录映射存储在磁盘上一个新的 hash partition 中的 hash bucket, 存储在 hash bucket 中的内容包含 sql 中的关于 B 的查询列,
连接列以及 hash_value_2 的值;
假设位图显示该 hash bucket 在 S[i] 中相应的记录数等于 0, 则说明这条记录不符合连接连接需舍弃.
【这个位图决定是否将 hash_value_1 所相应 B 中的记录写回到磁盘的动作就是所谓的位图过滤】
我们将 B 所相应的每个 hash partition 记为 B[j]。遍历完 B 中的全部记录, 构建 B[j] 完成.
3.2 再次构建 hash table
如今 oracle 已经处理完毕内存中的 S[i] 和 B[j], 仅仅剩下磁盘上的 S[i] 和 B[j] 还未处理.
因为构建 S[i] 和 B[j] 使用的同样的 hash 函数, 仅仅有相应 hash partition number 同样的 S[i] 和 B[j] 才有可能满足连接条件, 所以处理磁盘上的 S[i] 和 B[j] 仅仅需处理 hash partition number 同样的 S[i] 和 B[j].
对于每一对同样 hash partition number 的 S[i] 和 B[j], oracle 会选择记录数较少的当作驱动结果集, 同一时候依据 hash bucket 中 hash_value_2 构建新的 hash table,
记录数较多的当作被驱动结果集依据 hash_value_2 去匹配, 假设匹配成功, 则返回记录, 匹配不成功则丢弃.
【对于每一对同样 hash partition number 的 S[i] 和 B[j], oracle 会选择记录数较少的当作驱动结果集, 所以每一对同样 hash partition number 的 S[i] 和 B[j] 的驱动结果集都可能发生变化, 这就是动态角色互换】
处理完每一对同样 hash partition number 的 S[i] 和 B[j] 后, 哈希连接处理完毕.
二. hash 连接特性
1. hash 连接仅仅能用在等值连接条件
2. 驱动表的选择对运行效率及性能有影响
3. 驱动表和被驱动表最多被訪问一次
构造測试数据
SQL> CREATE TABLE t1 (
2 id NUMBER NOT NULL,
3 n NUMBER,
4 pad VARCHAR2(4000),
5 CONSTRAINT t1_pk PRIMARY KEY(id)
6 ); Table created. SQL> CREATE TABLE t2 (
2 id NUMBER NOT NULL,
3 t1_id NUMBER NOT NULL,
4 n NUMBER,
5 pad VARCHAR2(4000),
6 CONSTRAINT t2_pk PRIMARY KEY(id),
7 CONSTRAINT t2_t1_fk FOREIGN KEY (t1_id) REFERENCES t1
8 ); Table created. SQL> CREATE TABLE t3 (
2 id NUMBER NOT NULL,
3 t2_id NUMBER NOT NULL,
4 n NUMBER,
5 pad VARCHAR2(4000),
6 CONSTRAINT t3_pk PRIMARY KEY(id),
7 CONSTRAINT t3_t2_fk FOREIGN KEY (t2_id) REFERENCES t2
8 ); Table created.
SQL> CREATE TABLE t4 (
2 id NUMBER NOT NULL,
3 t3_id NUMBER NOT NULL,
4 n NUMBER,
5 pad VARCHAR2(4000),
6 CONSTRAINT t4_pk PRIMARY KEY(id),
7 CONSTRAINT t4_t3_fk FOREIGN KEY (t3_id) REFERENCES t3
8 ); Table created. SQL> execute dbms_random.seed(0) PL/SQL procedure successfully completed. SQL> INSERT INTO t1 SELECT rownum, rownum, dbms_random.string('a',50) FROM dual CONNECT BY level <= 10 ORDER BY dbms_random.random; 10 rows created. SQL> INSERT INTO t2 SELECT 100+rownum, t1.id, 100+rownum, t1.pad FROM t1, t1 dummy ORDER BY dbms_random.random; 100 rows created. SQL> INSERT INTO t3 SELECT 1000+rownum, t2.id, 1000+rownum, t2.pad FROM t2, t1 dummy ORDER BY dbms_random.random; 1000 rows created. SQL> INSERT INTO t4 SELECT 10000+rownum, t3.id, 10000+rownum, t3.pad FROM t3, t1 dummy ORDER BY dbms_random.random; 10000 rows created. SQL> COMMIT; Commit complete.
比較 hash 连接, nested loops 连接, sort merge join 连接
SQL> select * from t3, t4 where t3.id = t4.t3_id; 10000 rows selected. Execution Plan
----------------------------------------------------------
Plan hash value: 1396201636 ---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 1250K| 35 (3)| 00:00:01 |
|* 1 | HASH JOIN | | 10000 | 1250K| 35 (3)| 00:00:01 |
| 2 | TABLE ACCESS FULL| T3 | 1000 | 63000 | 5 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T4 | 10000 | 634K| 29 (0)| 00:00:01 |
--------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - access("T3"."ID"="T4"."T3_ID") Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
779 consistent gets
0 physical reads
0 redo size
1376470 bytes sent via SQL*Net to client
7745 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
10000 rows processed SQL> select /*+ leading(t3) use_nl(t4) */* from t3, t4 where t3.id = t4.t3_id; 10000 rows selected. Execution Plan
----------------------------------------------------------
Plan hash value: 2039660043 -----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 1250K| 11007 (1)| 00:02:13 |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 10000 | 1250K| 11007 (1)| 00:02:13 |
| 3 | TABLE ACCESS FULL | T3 | 1000 | 63000 | 5 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | T4_T3_ID | 10 | | 1 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| T4 | 10 | 650 | 11 (0)| 00:00:01 |
----------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 4 - access("T3"."ID"="T4"."T3_ID") Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
12605 consistent gets
0 physical reads
0 redo size
342258 bytes sent via SQL*Net to client
7745 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
10000 rows processed SQL> select /*+ leading(t3) use_merge(t4) */* from t3, t4 where t3.id = t4.t3_id; 10000 rows selected. Execution Plan
----------------------------------------------------------
Plan hash value: 3831111046 ------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 10000 | 1250K| | 193 (2)| 00:00:03 |
| 1 | MERGE JOIN | | 10000 | 1250K| | 193 (2)| 00:00:03 |
| 2 | SORT JOIN | | 1000 | 63000 | | 6 (17)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T3 | 1000 | 63000 | | 5 (0)| 00:00:01 |
|* 4 | SORT JOIN | | 10000 | 634K| 1592K| 187 (1)| 00:00:03 |
| 5 | TABLE ACCESS FULL| T4 | 10000 | 634K| | 29 (0)| 00:00:01 |
------------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 4 - access("T3"."ID"="T4"."T3_ID")
filter("T3"."ID"="T4"."T3_ID") Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
119 consistent gets
0 physical reads
0 redo size
344114 bytes sent via SQL*Net to client
7745 bytes received via SQL*Net from client
668 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
10000 rows processed
从上面的运行计划能够看出:
排序次数 | 逻辑读 | CPU Time | |
hash join | 0 | 779 | 00:01 |
nested loops | 0 | 12605 | 02:13 |
merge join | 2 | 119 | 00:03 |
可见。oracle 引入的 hash 连接, 可以解决嵌套循环连接中大量随机读的问题, 同一时候攻克了排序合并连接中排序代价过大的问题.
三. hash 连接优化
SQL> alter session set statistics_level=ALL;
SQL> select /*+ leading(t3) use_hash(t4) */* from t3, t4 where t3.id = t4.t3_id and t3.n = 1100; 10 rows selected. SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------- SQL_ID f57pu4khtptsc, child number 0
-------------------------------------
select /*+ leading(t3) use_hash(t4) */* from t3, t4 where t3.id =
t4.t3_id and t3.n = 1100 Plan hash value: 1396201636 ----------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.03 | 120 | | | |
|* 1 | HASH JOIN | | 1 | 10 | 10 |00:00:00.03 | 120 | 737K| 737K| 389K (0)|
|* 2 | TABLE ACCESS FULL| T3 | 1 | 1 | 1 |00:00:00.01 | 15 | | | |
| 3 | TABLE ACCESS FULL| T4 | 1 | 10000 | 10000 |00:00:00.01 | 105 | | | |
---------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - access("T3"."ID"="T4"."T3_ID")
2 - filter("T3"."N"=1100)
在表 T3 的谓词条件(n)上添加索引
SQL> create index t3_n on t3(n); Index created. SQL> select /*+ leading(t3) use_hash(t4) */* from t3, t4 where t3.id = t4.t3_id and t3.n = 1100; 10 rows selected. SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------- SQL_ID f57pu4khtptsc, child number 0
-------------------------------------
select /*+ leading(t3) use_hash(t4) */* from t3, t4 where t3.id =
t4.t3_id and t3.n = 1100 Plan hash value: 2452410886 --------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.03 | 108 | | | |
|* 1 | HASH JOIN | | 1 | 10 | 10 |00:00:00.03 | 108 | 737K| 737K| 389K (0)|
| 2 | TABLE ACCESS BY INDEX ROWID| T3 | 1 | 1 | 1 |00:00:00.01 | 3 | | | |
|* 3 | INDEX RANGE SCAN | T3_N | 1 | 1 | 1 |00:00:00.01 | 2 | | | |
| 4 | TABLE ACCESS FULL | T4 | 1 | 10000 | 10000 |00:00:00.01 | 105 | | | |
-------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - access("T3"."ID"="T4"."T3_ID")
3 - access("T3"."N"=1100)
从运行计划中可以看出 buffers 从 120 下降为 108, 可见谓词条件上的索引可以降低 hash 连接的逻辑读
接下来,看看在等值连接条件下,小表(小的结果集)为驱动表。hash 连接和 nested loop 嵌套循环连接
SQL> select * from t3, t4 where t3.id = t4.t3_id and t3.n = 1100; SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------- SQL_ID c204pd6srpjfq, child number 0
-------------------------------------
select * from t3, t4 where t3.id = t4.t3_id and t3.n = 1100 Plan hash value: 2039660043 ---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 29 |
| 1 | NESTED LOOPS | | 1 | | 10 |00:00:00.01 | 29 |
| 2 | NESTED LOOPS | | 1 | 10 | 10 |00:00:00.01 | 19 |
|* 3 | TABLE ACCESS FULL | T3 | 1 | 1 | 1 |00:00:00.01 | 16 |
|* 4 | INDEX RANGE SCAN | T4_T3_ID | 1 | 10 | 10 |00:00:00.01 | 3 |
| 5 | TABLE ACCESS BY INDEX ROWID| T4 | 10 | 10 | 10 |00:00:00.01 | 10 |
--------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 3 - filter("T3"."N"=1100)
4 - access("T3"."ID"="T4"."T3_ID") SQL> select * from t3, t4 where t3.id = t4.t3_id and t3.n = 1100; SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last')); PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------- SQL_ID c204pd6srpjfq, child number 0
-------------------------------------
select * from t3, t4 where t3.id = t4.t3_id and t3.n = 1100 Plan hash value: 2304842513 -------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.01 | 17 | 1 |
| 1 | NESTED LOOPS | | 1 | | 10 |00:00:00.01 | 17 | 1 |
| 2 | NESTED LOOPS | | 1 | 10 | 10 |00:00:00.01 | 7 | 1 |
| 3 | TABLE ACCESS BY INDEX ROWID| T3 | 1 | 1 | 1 |00:00:00.01 | 4 | 1 |
|* 4 | INDEX RANGE SCAN | T3_N | 1 | 1 | 1 |00:00:00.01 | 3 | 1 |
|* 5 | INDEX RANGE SCAN | T4_T3_ID | 1 | 10 | 10 |00:00:00.01 | 3 | 0 |
| 6 | TABLE ACCESS BY INDEX ROWID | T4 | 10 | 10 | 10 |00:00:00.01 | 10 | 0 |
------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 4 - access("T3"."N"=1100)
5 - access("T3"."ID"="T4"."T3_ID")
从上面的运行计划中能够看出, 採用 nested loops 嵌套循环连接的 CPU 0.03 降为 0.01, buffers 从 108 降为 17, 因此,在等值连接条件且在连接列条件上有索引, 假设返回的数据量较少, 适合用嵌套循环连接;
假设返回的数据量比較大, 则适合用 hash 连接。
四. 小结
在大多数的情况下, 哈希连接的效率比嵌套循环连接和排序合并连接更高:
1. 哈希连接可能比嵌套循环连接快,由于处理内存中的哈希表比检索B树更加迅速。
2. 哈希连接可能比排序合并连接更快,由于这样的情况下,仅仅有一张源表须要排序,并且仅仅是对 hash partition 排序。在排序合并连接中,两张表的数据都须要先做排序。然后做MERGE操作,因此效率相对最差。
hash 连接非常适合一大一小的结果集连接返回大数据量的情形, 特别是 hash table 可以所有放在 hash area 的情况下, 这时候哈希连接的运行时间可以近似看做是全表扫描两个结果集的时间之和.
在 sql 调优时, 假设遇到表的连接方式是 hash 连接, 进行优化能够考虑下面几点:
1. 确认小结果集为驱动结果集
2. 假设有谓词条件, 考虑在谓词条件上添加索引
3. 确认涉及到的表和连接列被分析过, 假设连接列上的数据分布不均匀, 考虑在此列上收集直方图
4. 添加 hash_area_size 大小, 使哈希连接仅仅在内存就能完毕, 即保证 PGA hash area 可以容纳 hash 运算
參考: http://www.dbsnake.net/oracle-hash-join.html
oracle 表连接 - hash join 哈希连接的更多相关文章
- SWAP_JOIN_INPUTS Oracle Hint(处理hash join强制大表(segment_size大)作为被驱动表)
SWAP_JOIN_INPUTS Oracle Hint(处理hash join强制大表(segment_size大)作为被驱动表) swap_join_inputs是针对哈希连接的hint,它的含义 ...
- OLAP 大表和小表并行hash join
一个表50MB 一个表10GB 50M表做驱动表,放在PGA里 这时候慢在对对 10g 的全表扫描 对10个G扫描块 需要开并行 我有这样一个算法 一个进程 读 50mb 8进程 来 扫描 10gb ...
- 哈希连接(hash join) 原理
哈希连接(hashjoin) 访问次数:驱动表和被驱动表都只会访问0次或1次. 驱动表是否有顺序:有. 是否要排序:否. 应用场景: 1. 一个大表,一个小表的关联: ...
- Oracle 左连接 left join、右连接right join说明
Oracle 左.右连接 + 在等号 左边表示右连接 获取右表所有记录,即使左表没有对应匹配的记录. + 在等号 右边表示左连接 获取左表所有记录,即使右表没有对应匹配的记录. 例子: selec ...
- 数据库中的左连接(left join)和右连接(right join)区别
Left Join / Right Join /inner join相关 关于左连接和右连接总结性的一句话: 左连接where只影向右表,右连接where只影响左表. Left Join select ...
- 数据库左连接left join、右连接right join、内连接inner join on 及 where条件查询的区别
join on 与 where 条件的执行先后顺序: join on 条件先执行,where条件后执行:join on的条件在连接表时过滤,而where则是在生成中间表后对临时表过滤 left joi ...
- Bullet:关于ORACLE中的HASH JOIN的参数变化
Oracle在7.3引入了hash join. 但是在Oracle 10g及其以后的Oracle数据库版本中,优化器,实际是CBO,也是因为HASH JOIN仅适用于CBO,在解析目标SQL时是否考虑 ...
- oracle多表连接方式Hash Join Nested Loop Join Merge Join
在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式: 嵌套循环(Nested Loops (NL) ...
- Oracle 三种连接方式 NESTED LOOP HASH JOIN SORT MERGE JOIN
NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大( ...
随机推荐
- iOS开发之计算动态cell的高度并缓存
项目中有个类似微博那样的动态cell,文字和图片的多少都不是确定的 刚开始使用autolayout,结果很多问题,最后我发现了一个框架 FDTemplateLayoutCell 写的很好,自动布局ce ...
- 转:javascript面向对象编程
作者: 阮一峰 日期: 2010年5月17日 学习Javascript,最难的地方是什么? 我觉得,Object(对象)最难.因为Javascript的Object模型很独特,和其他语言都不一样,初学 ...
- python 字符串处理
介绍字符串相关的:比较,截取,替换,长度,连接,反转,编码,格式化,查找,复制,大小写,分割等操作 什么是字符串 字符串 字符串或串(String)是由数字.字母.下划线组成的一串字符.一般记为 s= ...
- (未解决)在JSTL中,session 和 sessionScope 有什么区别 ??
在JSP页面中,使用JSTL标签获取Session中的值并显示 为何当使用 ${session.user} 时,页面跳转后,第一次能够成功显示, 但是单击按钮重定向的时候,就获取不到了? 而使用 ${ ...
- grep命令參数及使用方法
功能说明:查找文件中符合条件的字符串. 语 法:grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>] ...
- Lua学习笔记6:C++和Lua的相互调用
曾经一直用C++写代码.话说近期刚换工作.项目组中的是cocos2dx-lua,各种被虐的非常慘啊有木有. 新建cocos2dx-lua项目.打开class能够发现,事实上就是C++项 ...
- 大整数乘法python3实现
因为python具有无限精度的int类型,所以用python实现大整数乘法是没意义的,可是思想是一样的.利用的规律是:第一个数的第i位和第二个数大第j位相乘,一定累加到结果的第i+j位上,这里是从0位 ...
- 简单字符串处理 hdu1062 Text Reverse
虽然这个题目一遍AC,但是心里还是忍不住骂了句shit! 花了一个小时,这个题目已经水到一定程度了,但是我却在反转这个操作上含糊不清,并且还是在采用了辅助数组的情况下,关系的理顺都如此之难. 其实我是 ...
- 80端口的烦恼:[3]清除NT Kernel占用80端口
链接地址:http://jingyan.baidu.com/article/f96699bbca15a1894e3c1bc4.html 当一台电脑安装了vs又安装了xampp时,可以能发生80端口号冲 ...
- cocos2d-x游戏开发系列教程-中国象棋00-前言
象棋描述 在说代码之前,我们先让象棋效果登场,以方便大家对代码的理解 欢迎界面 中国象棋程序,运行起来的第一个界面是一个欢迎界面,该欢迎界面在停留一秒后进入游戏界面 游戏主界面 新局:所有棋子归位,状 ...