Consistent gets 的理解

Consistent gets 与db block gets的区别很明显,后者指DML访问,前者指SELECT访问,这里的一致性读不表示从回滚块组织一致性数据,意思是以保证一致性为目标的读。DML不需要保证一致性,所以直接读data block。


Consistent gets 的值是怎么得来,有何意义,现在也并不很明白。计算公式差不多等于:

SELECT COUNT(*) FROM T5;得到的Consistent gets + (结果集的行数rows / arraySize);

也有很多COPY一遍又一遍的文章说是rows/arraySize + blocks

指代的意义,是这次查询扫描了几次数据块,并不是几个数据块。开始我一直没想到这里。

现在的理解还是比较模糊,仅供参考:

在没有索引的表上面条件查询时,先进行全表扫描,得到完整结果集,服务端组织数据到SQLPLUS显示,由于设置了arraySize分页,默认15,那么服务器与客户端网络上往返的次数会跟这个arraySize有关。如果<15条数据,得到一次,如果是50条数据,得到4次。再加上count得到的值。

但是大数据量的时候这个公式还是不准确。

create table T5
(
  id   NUMBER(9),
  age  NUMBER(9),
  name VARCHAR2(888)
)

begin
  for i in 1..50
    loop
      insert into t5 values(i,99,'TOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMYTOMMY');
      END LOOP;
      COMMIT;
      END;

查数据库分布:
SQL> SELECT dbms_rowid.rowid_block_number(ROWID) L,COUNT(*) FROM T5 GROUP BY dbms_rowid.rowid_block_number(ROWID);
 
         L   COUNT(*)
---------- ----------
       189         12
       191         12
       188          2
       190         12
       192         12
SQL> select blocks from user_segments where segment_name ='T5';
 
    BLOCKS
----------
         8

SQL> SELECT blocks,empty_blocks FROM USER_TABLES T WHERE T.TABLE_NAME='T5';
 
    BLOCKS EMPTY_BLOCKS
---------- ------------
         5            3

总共50条记录。分布在5个数据块。另外有三个空块。

但是,上面第一个使用ROWID_BLOCK_NUMBER的查询在数据量大的时候与USER_TABLES表明的块数量会不一样。这些是有差别的。

进入SQLPLUS

多次查询保证没有物理读。

SQL> set autotrace traceonly statistics;
SQL> select count(*) from t5;


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          7  consistent gets
          0  physical reads
          0  redo size
        408  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

COUNT(*) = 7。这7个里面,先是访问了5个数据块,从块头读到记录行数(或者扫描块体),另外的两个就不得而知了。

当进行条件查询时,仍然进行全表扫描,这时就以这个7为基数,然后加上因为arraySize导致的客户端服务端往返的重复扫描同一个块的次数。

所以过程可能是:第一步执行所有数据块的全部扫描,得到7次,然后会确定结果集的分布情况,分布在哪些数据块里面,接下来再到这些块里面提取行,提取的过程因为arraySize所以可能会多次进入同一个块提取。

(===================如果是这样:第一步扫描完所有块,得到一个结果集,服务端保留这个结果集为临时数据,然后根据arraySize分成一次或几次发送到客户端,那么后面几次到服务端取数据时就不用访问数据块,所以第一步应该只是确定数据分布吧)

SQL> show array
arraysize 10

SQL> set array 15

array和arraysize是一样的

SQL> select * from t5;

已选择50行。


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         11  consistent gets
          0  physical reads
          0  redo size
      29829  bytes sent via SQL*Net to client
        418  bytes received via SQL*Net from client
          5  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         50  rows processed

然后改arraysize。重新查询。依次得到

1/2>>32gets

3>>24

4>>20

5/6>>16

7/8>>14

9>>13

10/11/12>>12

13>>10

14/15>>11

20>>10

50>>8

100>>8
这里array=1时只出现了32次,可能是有一些细节处理的机制。因为这些机制,特别是大数据量的时候就不一定准确了。
接下来条件查询:

SQL> select * from t5 where id<=1;


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
       1077  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL> select * from t5 where id<=15;

已选择15行。


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
       1220  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
 15  rows processed

改条件,依次得到:

id<=15---------------------------------------8

15<id<=30 ---------------------------------------9

30<id<=45 ---------------------------------------10

45<id ---------------------------------------11

所以,关键应该在于数据集通过arraySize分页的过程中。

另外还有一个fetchSize,SQLPLUS里面没有这个值,JAVA里面可以设置,好像是一个用处

下面设置索引

SQL> CREATE INDEX I_1 ON T5(ID);

索引已创建。

全部查询统计信息还是一样。COUNT(*) 也没有变。

条件查询就不一样了。

SQL> SELECT * FROM T5 WHERE ID=5;


执行计划
----------------------------------------------------------
Plan hash value: 4059149231

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |     1 |   564 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T5   |     1 |   564 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | I_1  |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID"=5)


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
       1083  bytes sent via SQL*Net to client
        385  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

这里数据块可能只扫描了一次,而索引块扫描了两次。

所以关键之处,应该在于理解服务端提取数据的步骤。分成两步,第一步是服务端查询出所有结果集,第二步是分次数发送到客户端。

SQL> SELECT * FROM T5 WHERE ID<=20;

已选择20行。


执行计划
----------------------------------------------------------
Plan hash value: 2002323537

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    20 | 11280 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T5   |    20 | 11280 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("ID"<=20)


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          9  consistent gets
          0  physical reads
          0  redo size
       1387  bytes sent via SQL*Net to client
        396  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         20  rows processed

当ID<=19时还是选择的索引范围扫描,当ID<=20时,就变成了全表扫描。因为优化器估算出使用索引可能比全部扫描访问的块更多。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ConsistentHash是一种在分布式系统中解决数据分片、负载均衡的算法,用于解决数据分布和节点动态变化的问题。在Java中,可以通过实现ConsistentHash算法来分配数据并达到负载均衡的效果。 在Java中,可以使用TreeMap或者HashMap作为底层数据结构来实现ConsistentHash算法。TreeMap可以保证数据有序性,HashMap则可以提供更快的插入和查询速度。我们在这里以TreeMap为例来说明ConsistentHash的实现过程。 首先,我们需要创建一个哈希函数,将节点的IP地址或者ID映射为整数,作为节点的哈希值。然后,我们在TreeMap中存储节点的哈希值和对应的物理节点信息。 当有新的数据需要插入时,将数据的哈希值通过哈希函数计算得到对应的整数。然后,在TreeMap中找到大于等于该哈希值的最小键值对应的物理节点,将数据保存在该节点上。 当节点动态增加或删除时,我们需要重新计算所有已存在数据的哈希值,并将数据重新分配到新的节点上,以保持数据的均匀分布。 通过使用ConsistentHash算法,我们可以实现数据的分片存储和负载均衡,使得在节点动态变化的情况下,系统的性能和可扩展性得到有效的提升。 总之,ConsistentHash算法是一种在分布式系统中解决数据分片、负载均衡问题的算法。在Java中,我们可以通过实现ConsistentHash算法,使用TreeMap或者HashMap来实现数据分配和节点动态变化的管理。这样可以有效提高系统的性能和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值