【Oracle Database 12c New Feature】How to Learn Oracle (12c New Feature) from Error

这篇文章也许并不太牵涉什么技术点,只是描述一下我自己在学习的时候大概是什么状态,什么思路,因为自认自己的学习能力还不错,因此也期望这样的学习方法对其他人会有帮助。看这篇文章的时候,你可以同步地想一想如果是你遇到这样的错误,你会怎么处理,怎么发散,怎么研究?

Oracle Database 12c前几天正式发布了,如果学习一个新版本的数据库?我通常是从New Features Guide文档看起,先通览文档的目录,遇到感兴趣的新功能点,就开始做实验来验证这个新功能。当然,这之前需要先把新版本的数据库安装好,先把新版本的全部文档下载到本地,这样即使你坐在飞机上也可以有文档可查。

这次我的计划是实验一下Identity类型的字段,这个字段可以用来作主键,会自动递增,这种类型的字段在SQL Server中早就存在,但是Oracle直到12c才推出这个功能。

通常我不会用sys用户进行任何实验(除非是验证sysdba的新功能),因此总是会先创建一个我自己的dba用户。
在12c中创建这个用户首先就遇到了错误。

SQL> create user kamus identified by oracle default tablespace users;
create user kamus identified by oracle default tablespace users
            *
ERROR at line 1:
ORA-65096: invalid common user or role name

对于一个不熟悉的错误,第一件事情不是去Google(如果你说Baidu那就更幼稚了),而是用oerr实用程序来看看Oracle自己对这个错误是怎么解释的。为什么我喜欢非Windows环境中的Oracle?oerr的存在也是很大一个原因。

[oracle@dbserver-oel ~]$ oerr ora 65096
65096, 00000, "invalid common user or role name"
// *Cause:  An attempt was made to create a common user or role with a name
//          that wass not valid for common users or roles.  In addition to
//          the usual rules for user and role names, common user and role
//          names must start with C## or c## and consist only of ASCII
//          characters.
// *Action: Specify a valid common user or role name.
//

错误信息的解析非常明确地告知“试图创建一个通用用户,必需要用C##或者c##开头”,这时候心里会有疑问,什么是common user?但是我通常不会先急着去翻文档,而是先把手头的事情做完,也就是先把用户创建上。

SQL> create user c##kamus identified by oracle default tablespace users;

User created.

SQL> grant dba to c##kamus;

Grant succeeded.

SQL> select USERNAME,COMMON,ORACLE_MAINTAINED from dba_users;

USERNAME                       COM O
------------------------------ --- -
AUDSYS                         YES Y
GSMUSER                        YES Y
SPATIAL_WFS_ADMIN_USR          YES Y
SPATIAL_CSW_ADMIN_USR          YES Y
APEX_PUBLIC_USER               YES Y
SYSDG                          YES Y
DIP                            YES Y
SYSBACKUP                      YES Y
MDDATA                         YES Y
GSMCATUSER                     YES Y
C##KAMUS                       YES N
SYSKM                          YES Y
XS$NULL                        YES Y
OJVMSYS                        YES Y
ORACLE_OCM                     YES Y
OLAPSYS                        YES Y
SI_INFORMTN_SCHEMA             YES Y
DVSYS                          YES Y
ORDPLUGINS                     YES Y
XDB                            YES Y
ANONYMOUS                      YES Y
CTXSYS                         YES Y
ORDDATA                        YES Y
GSMADMIN_INTERNAL              YES Y
APPQOSSYS                      YES Y
APEX_040200                    YES Y
WMSYS                          YES Y
DBSNMP                         YES Y
ORDSYS                         YES Y
MDSYS                          YES Y
DVF                            YES Y
FLOWS_FILES                    YES Y
SYS                            YES Y
SYSTEM                         YES Y
OUTLN                          YES Y
LBACSYS                        YES Y

36 rows selected.

创建C##KAMUS用户成功之后,再返回去解决心中的疑问,什么是common user?在联机文档的左上角搜索关键字common user,会得到如下的结果。
Oracle Online Doc Search Result

通常我会先浏览Concept,如果看完觉得心中疑问已经解决,就会返回继续作之前的实验,不会再浏览其他的链接;如果想要查询怎么做,比如说如何创建Common User,才会继续去看Task部分。这样的好处是可以保持专注而不至于被过多文档分心

但是由于Common User这个概念几乎是崭新的,所以我很有兴趣继续探索一下,跟Common User相对的Local User该如何创建。继续去看Task当然是个方法,但是这里我选择的是直接去看SQL Language Reference,因为我们知道一定是在Create User语法里面会有不同的定义,进入Create User语法页面,直接搜索common user,就可以看到如下这段话。

CONTAINER Clause

To create a local user in a pluggable database (PDB), ensure that the current container is that PDB and specify CONTAINER = CURRENT. To create a common user, ensure that the current container is the root and specify CONTAINER = ALL. The name of the common user must begin with C## or c##. If you omit this clause and the current container is a PDB, then CONTAINER = CURRENT is the default. If you omit this clause and the current container is the root, then CONTAINER = ALL is the default.

也就是说我们一定要先登录进一个PDB,才可以创建本地用户,那么如何知道现在的sqlplus是登录进了哪个DB呢?这个疑问其实是一个很简单的联想,既然需要去一个地方,那么一定有方法知道我现在在什么地方,通过简单地查询文档,可以得知以下的方法。现在确实在CDB中。

SQL> show con_name

CON_NAME
------------------------------
CDBROOT

SQL> SELECT SYS_CONTEXT ('USERENV', 'CON_NAME') FROM DUAL;

SYS_CONTEXT('USERENV','CON_NAME')
-----------------------------------------------
CDBROOT

dbca建库的时候,有一个新选项是同时创建PDB,我勾选过(对于dbca中出现的新选项,如果不是条件不允许,我都会选中进行测试),创建了名字为pdbtest的PDB,那么现在我想尝试登录这个PDB,去创建一个Local User。如何登录PDB?Administrator’s Guide中有专门新的一个章节“Part VI Managing a Multitenant Environment”来描述如何管理多租户环境,浏览目录就可以直接找到“Connecting to a PDB with SQL*Plus”这部分,如下所示。

You can use the following techniques to connect to a PDB with the SQL*Plus CONNECT command:

Database connection using easy connect
Database connection using a net service name

那尝试直接使用easy connect来登录PDB。

$ sqlplus sys/oracle@127.0.0.1:15210/pdbtest as sysdba

SQL*Plus: Release 10.2.0.4.0 - Production on Sat Jul 6 21:44:42 2013

Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options

SQL>  SELECT SYS_CONTEXT ('USERENV', 'CON_NAME') FROM DUAL;

SYS_CONTEXT('USERENV','CON_NAME')
------------------------------------------
PDBTEST

Elapsed: 00:00:00.01

SQL>  select NAME,PDB from dba_services;
 select NAME,PDB from dba_services
                      *
ERROR at line 1:
ORA-01219: database or pluggable database not open: queries allowed on fixed tables or views only

PDB没有Open?尝试打开。无法使用startup命令。这是显而易见的。 原因是我使用了旧版本的SQL*Plus(如上所示是10.2.0.4.0)连接到12c数据库的PDB中,某些新特性不被支持。

SQL> startup
ORA-24543: instance startup or shutdown not allowed in pluggable database

使用12c自带的SQL*Plus登录,就可以使用startup命令将PDB打开,使用SQL*Plus管理PDB的详细命令可以参看文档描述

SQL> show user
USER is "SYS"
SQL> startup
Pluggable Database opened.
SQL>
SQL> show con_name

CON_NAME
------------------------------
PDBTEST

或者可以使用如下语句打开PDB。

SQL> ALTER PLUGGABLE DATABASE OPEN;

Operation 227 succeeded.

Elapsed: 00:00:02.44

SQL> SELECT NAME, OPEN_MODE, RESTRICTED, OPEN_TIME FROM V$PDBS;

NAME			       OPEN_MODE  RES OPEN_TIME
------------------------------ ---------- --- ------------------------------------------------
PDBTEST 		       READ WRITE NO  06-JUL-13 09.48.57.260 PM

到此,可以创建Local User了。

SQL> create user kamus identified by oracle;

User created.

Elapsed: 00:00:00.10
SQL> grant dba to kamus;

Grant succeeded.

Elapsed: 00:00:00.03

那么在一个PDB中可以看到多少用户呢?可以看到CDB中的用户吗?这又是一个简单的联想,学习的过程其实是一个发散再收缩的循环。看来不可以,只能看到自己的用户,当然这里有很多Common User。可以看到即使是在PDB中,cdb_视图也是可以使用的。

SQL> select CON_ID,count(*) from cdb_users group by con_id;

    CON_ID   COUNT(*)
---------- ----------
	 3	   38

Elapsed: 00:00:00.03

那么再回到CDB中看一下,会是什么情况?可以看到所有Container中的用户都可以查询到。

SQL> select CON_ID,count(*) from cdb_users group by con_id;

    CON_ID   COUNT(*)
---------- ----------
         1         36
         2         35
         3         38

Elapsed: 00:00:00.08

终于,我可以回到最开始的实验目标上去了,在PDB中创建了T1表,id列为Identity类型。

SQL> CREATE TABLE t1 (id NUMBER GENERATED AS IDENTITY);

Table created.

Elapsed: 00:00:00.22

根据文档描述,Identity类型仍然是通过Sequence来实现的,那么应该是自动创建了一个Sequence,果然如此。在你学习的过程中会多此一步来查询一下Sequence视图吗?


默认创建的Sequence,CACHE_SIZE是20,开始值是1,这都跟单独创建的Sequence默认值一样。


插入一条数据试一下,报错报错还是报错。所以如果是generated always的identity列,如果只有这一列,没法插入数据。

SQL> insert into t1 values('');
insert into t1 values('')
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column


Elapsed: 00:00:00.01

SQL> insert into t1 values(ISEQ_91620.nextval);
insert into t1 values(ISEQ_91620.nextval)
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column


Elapsed: 00:00:00.00

SQL> insert into t1 values(null);
insert into t1 values(null)
*
ERROR at line 1:
ORA-32795: cannot insert into a generated always identity column


Elapsed: 00:00:00.00

换GENERATED BY DEFAULT ON NULL 类型试一下,Wait,如果删除了表,对应的序列会自动删除吗?理论上应该会,当然还是要测试一下。

SQL> drop table t1;

Table dropped.

Elapsed: 00:00:00.19

序列还在?


再建一张表。

SQL> CREATE TABLE t2 (id NUMBER GENERATED BY DEFAULT AS IDENTITY);

Table created.

Elapsed: 00:00:00.01

现在是2个序列了。

SQL> select * from user_sequences;

SEQUENCE_NAME															  MIN_VALUE  MAX_VALUE
-------------------------------------------------------------------------------------------------------------------------------- ---------- ----------
INCREMENT_BY C O CACHE_SIZE LAST_NUMBER PARTITION_COUNT S K
------------ - - ---------- ----------- --------------- - -
ISEQ_91620																  1 1.0000E+28
	   1 N N	 20	      1 		N N

ISEQ_91622																  1 1.0000E+28
	   1 N N	 20	      1 		N N


Elapsed: 00:00:00.00

写完整的Drop语句试一下。

SQL> drop table t2 cascade constraint purge;

Table dropped.

Elapsed: 00:00:00.12

后创建的序列已经被自动删除了,之前创建的还在。


两者的不同应该是purge,如果被删除的表还在回收站中,序列是会保留的,Make sense,因为表还可能从回收站里面再restore回来,需要保证序列仍然有效。那么清空回收站实验一下。

SQL> purge recyclebin;

Recyclebin purged.

Elapsed: 00:00:00.04

果然,序列也相应地被删除了。

SQL> select * from user_sequences;

no rows selected

Elapsed: 00:00:00.00

再回到正题,创建T3表,插入一条数据。

SQL> CREATE TABLE t3 (id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY);

Table created.

Elapsed: 00:00:00.01
SQL> insert into t3 values(null);

1 row created.

Elapsed: 00:00:00.01

序列的LAST_NUMBER已经增加为21。


后台如何操作的?使用10046 trace,再插入几条数据。

SQL> insert into t3 values(null);

1 row created.

SQL> insert into t3 values(null);

1 row created.

SQL> select * from t3;

	ID
----------
	 1
	 2
	 3

到此为止,可以休息一下了,从ORA-65096开始大概花费了1个多小时的时间,我学习到了:
1. 什么是Common User,什么是Local User?
2. 如何查询现在的环境是CDB还是某个PDB?
3. 如何登录PDB?
4. 如何启动PDB?
5. PDB和CDB中视图看到的内容有怎样的不同?
6. 如何创建Identity类型的列?
7. 删除表以后,对应的Sequence如何处理?
8. Oracle后台对于Identity列是如何处理的?

你是不是也是这样学习的呢?

Update@2013-07-15
谢谢留言中Asher的建议,增加如下测试。
使用DBMS_METADATA.GET_DDL获取到的DDL信息,已经是符合12c语法的样式了,显示出了Sequence的具体信息。

SQL> select dbms_metadata.GET_DDL('TABLE','T3') from dual;

DBMS_METADATA.GET_DDL('TABLE','T3')
--------------------------------------------------------------------------------

  CREATE TABLE "KAMUS"."T3"
   (	"ID" NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 99
99999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE
  NOT NULL ENABLE,
	"COMMENTS" VARCHAR2(100)
   ) SEGMENT CREATION IMMEDIATE
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS"

系统自动产生的序列无法手工修改属性。

SQL> alter sequence "ISEQ_91624" INCREMENT BY 10;
alter sequence "ISEQ_91624" INCREMENT BY 10
*
ERROR at line 1:
ORA-32793: cannot alter a system-generated sequence

SQL> host oerr ora 32793
32793,0000, "cannot alter a system-generated sequence"
// *Cause:  An attempt was made to alter a system-generated sequence.
// *Action: A system-generated sequence, such as one created for an
//          identity column, cannot be altered.

系统自动产生的序列也不允许删除。

SQL> drop sequence "ISEQ_91624";
drop sequence "ISEQ_91624"
              *
ERROR at line 1:
ORA-32794: cannot drop a system-generated sequence

SQL> host oerr ora 32794
32794,0000, "cannot drop a system-generated sequence"
// *Cause:  An attempt was made to drop a system-generated sequence.
// *Action: A system-generated sequence, such as one created for an
//          identity column, cannot be dropped.

在11gR2中错误信息编号在ORA-32790和ORA-32800之间是空白,而12c使用了这其间的8个错误号作为新特性的报错。

ORA-32791: prebuilt table managed column cannot have a default on null
Cause: An attempt was made to create a materialized view on a prebuilt table that has a managed column with a default on null expression.
Action: Either remove the default on null property, or do not include the column in the materialized view definition.

ORA-32792: prebuilt table managed column cannot be an identity column
Cause: An attempt was made to create a materialized view on a prebuilt table that has a managed column that is an identity column.
Action: Either remove the identity property, or do not include the column in the materialized view definition.

ORA-32793: cannot alter a system-generated sequence
Cause: An attempt was made to alter a system-generated sequence.
Action: A system-generated sequence, such as one created for an identity column, cannot be altered.

ORA-32794: cannot drop a system-generated sequence
Cause: An attempt was made to drop a system-generated sequence.
Action: A system-generated sequence, such as one created for an identity column, cannot be dropped.

ORA-32795: cannot insert into a generated always identity column
Cause: An attempt was made to insert a value into an identity column created with GENERATED ALWAYS keywords.
Action: A generated always identity column cannot be directly inserted. Instead, the associated sequence generator must provide the value.

ORA-32796: cannot update a generated always identity column
Cause: An attempt was made to update an identity column created with GENERATED ALWAYS keywords.
Action: A generated always identity column cannot be directly updated.

ORA-32797: identity column sequence mismatch in ALTER TABLE EXCHANGE PARTITION
Cause: The two tables specified in the EXCHANGE have identity columns with sequences that are neither both increasing nor decreasing.
Action: Ensure that the identity columns have sequences with INCREMENT BY having the same sign.

ORA-32798: cannot use ANSI RIGHT or FULL outer join with a left correlation
Cause: An attempt was made to use a lateral view with a left correlation to the first operand of an ANSI RIGHT or FULL outer join.
Action: Rewrite the query without the left correlation.

【Oracle Database 12c New Feature】What’s New in DBCA of Oracle Database 12c

Oracle Database 12c已经正式发布,在创建数据库的dbca程序界面上与以往的版本有哪些不同?

1. 出现了Manage Pluggable Databases的选项。 PDB是Oracle12c大力宣传的一个新特性,参看文档
Step 1

2. 如果安装的机器上已经有11g GI,那么会出现警告,提升要么升级到12.1,要么新创建的数据库将无法假如到GI的管理中。

Step 2

3. 创建数据库的时候,可以直接选择是CDB还是Non-CDB,也可以同时创建多个PDB。
Step 3

4. 更多的权限细分group,但是在我遇见的生产环境中,很少有使用到这样细分的权限。通常都是一个dba组搞定全部。
Step 4

5. 以往的版本在最后一步真正开始创建数据库的时候是弹出一个新窗口,12c嵌入到dbca的整体界面中。最人性化的改变是可以直接查看alert日志,并且内容是自动滚动的。不再需要登录到服务器上tail -f了。
Step 5

About GETS, MISSES, SPIN_GETS, SLEEPS in V$LATCH

今天重新阅读Latch的文档,按照我自己的理解,对于vlatch视图中的以下几个字段再作一些解释。
以下参数都是对于Willing-to-wait模式的latch而言的,no-wait模式的latch获得情况统计值则在IMMEDIATE_GETS和IMMEDIATE_MISSES字段中。所有v
latch视图中统计值都是在获得了latch之后才更新的。

GETS:当尝试获取一个latch并最终获得的时候,该值加1,在一次请求中无论是经过多少次自旋多少次Sleep,该值只会加1.

MISSES:如果没能不经过自旋(spin)就获得latch,该值加1,在一次请求中无论是经过多少次自旋多少次Sleep,该值只会加1.

SPIN_GETS:如果经过自旋才获得latch,该值加1,在一次请求中无论是经过多少次自旋,该值只会加1;如果经过了下述的SLEEPS方式才获得的latch,那么该值不变。

SLEEPS:这是MISS之后进程除了自旋之外,可能采取的另外一种方式-睡眠,将等待信号量唤醒或者Timeout唤醒。可能是由于多次自旋以后,仍然无法获得latch,进程就停止占用CPU,进入Sleep状态;也可能是首次尝试获取latch失败以后就直接进入睡眠期(比如单个CPU的机器中)。Sleep以后获得latch,该值加1,如果一次Sleep以后被唤醒,但是却仍然无法获得latch,那么会再次自旋,还无法获得,再次Sleep(睡眠时间会逐渐变长),多次Sleep会累加该值。

SQL> select count(*) from v$latch where MISSES=0;

  COUNT(*)
----------
       484

如上所示,这些latch都是一次请求就直接成功了,连一次Miss都没有。只要MISSES=0,那么SPIN_GETS和SLEEPS也一定等于0。

SQL> select NAME,GETS,MISSES,SPIN_GETS,SLEEPS from v$latch where MISSES>0 and SLEEPS=0;

NAME                                           GETS     MISSES  SPIN_GETS     SLEEPS
---------------------------------------- ---------- ---------- ---------- ----------
process allocation                            31557          8          8          0
session switching                             32313          3          3          0
process group creation                        24916          1          1          0
object stats modification                    171932         93         93          0
parameter table management                    38297         28         28          0
enqueue freelist latch                          407         28         28          0
FOB s.o list latch                            68402         13         13          0
FIB s.o chain latch                             416          1          1          0
resmgr:free threads list                      29002         55         55          0
resmgr group change latch                   1691466         79         79          0
channel handle pool latch                     28121          4          4          0
message pool operations parent latch          97758        128        128          0
ksv class latch                               25738         66         66          0
OS process allocation                       2402435          7          7          0
ksz_so allocation latch                       24916          8          8          0
mostly latch-free SCN                        931660        715        715          0
lgwr LWN SCN                                 930897         73         73          0
Consistent RBA                               807421         43         43          0
multiblock read objects                      256976         10         10          0
cache table scan latch                        95413          5          5          0
managed standby latch                         32933         15         15          0
list of block allocation                      64850         24         24          0
transaction allocation                       199415         55         55          0
KTF sga latch                                  7195          2          2          0
resmgr:resource group CPU method               8868         21         21          0
parameter list                                59369          8          8          0
job_queue_processes free list latch             699          1          1          0
process queue reference                        5500          1          1          0
parallel query alloc buffer                  163672          1          1          0
hash table modification latch                 52632          6          6          0
temporary table state object allocation        2939         14         14          0
SQL memory manager latch                      41293          1          1          0
SQL memory manager workarea list latch     28598806         49         49          0
session state list latch                      34530          1          1          0

34 rows selected.

如上所示,这些latch都有请求没有立刻成功的情况,因此都需要Spin片刻然后再次尝试获取,但是却都在Spin一次或者几次以后(在第一次Sleep之前最多自旋2000次,受隐含参数_spin_count控制)就成功获得了latch,注意所有行的MISSES=SPIN_GETS,也就是说如果某个latch在被尝试获取的时候从来都没有让进程Sleep过,那么只要出现1次Miss,就必须有至少1次Spin,而直到成功获得latch之前,无论有多少次Spin,SPIN_GETS值都始终只是加了1。

SQL> select NAME,GETS,MISSES,SPIN_GETS,SLEEPS from v$latch where MISSES>0 and MISSES<>SPIN_GETS;

NAME                                           GETS     MISSES  SPIN_GETS     SLEEPS
---------------------------------------- ---------- ---------- ---------- ----------
post/wait queue                             2176086       6243       6215         28
call allocation                              140862         79         50         29
session allocation                          1366266        208        194         14
session idle bit                           21495388       2581       2552         29
ksuosstats global area                       124206         13          0         13
messages                                   16534632       7141       7076         66
enqueue hash chains                        14685159       6740       6613        127
channel operations parent latch             6197125        261        233         28
active service list                         1343611         36         17         19
OS process: request allocation                24916         16          7          9
cache buffers lru chain                     3932233       3750       3587        166
active checkpoint queue latch               1657410        315        283         32
checkpoint queue latch                     36991888        796        759         37
cache buffers chains                      385956869      13902      13573        335
cache buffer handles                         115915          1          0          1
simulator lru latch                         1730616         70         61          9
simulator hash latch                       11343463         16         11          5
object queue header operation              24499957       7389       7149        241
object queue header heap                    6170931        465        459          6
archive process latch                         99017         77         12         65
redo writing                                4799991       1133       1131          2
redo allocation                             2703585       1256       1022        234
DML lock allocation                         2340322        302        291         11
dummy allocation                              25610         44         26         18
undo global data                            5721900       1143       1126         17
sort extent pool                              55723         88         87          1
space background task latch                 1653230      12640      12624         17
sequence cache                                37261          6          0          7
row cache objects                          57918735     298666     298342        334
shared pool                                14914798      80691      71271      12265
resmgr:actses change state                    12453          1          0          1
resmgr:schema config                        1792347       2144       2124         20
shared pool simulator                        645495         44         43          1
hash table column usage latch                 73186        300        299          1
qmn task queue latch                         179150          8          0          8

35 rows selected.

如上所示,只要曾经MISS过,但MISSES<>SPIN_GETS,那么必然意味着会有SLEEPS出现。SLEEPS之后,就不再累加本次的SPIN_GETS,因此所有的SPIN_GETS值才会都小于MISSES。
注意到其中有多个latch,完全没有经过Spin,而是每次都直接Sleep了,我的理解是对于某些latch,Oracle就直接选择了Sleep方式而不会尝试自旋(即使是在多CPU机器中)。以下这些latch都是这种模式,不会进行Spin,而是直接进入Sleep状态,等待唤醒然后再尝试获取latch。

SQL> select NAME,GETS,MISSES,SPIN_GETS,SLEEPS from v$latch where SPIN_GETS=0 and SLEEPS>0;

NAME                                           GETS     MISSES  SPIN_GETS     SLEEPS
---------------------------------------- ---------- ---------- ---------- ----------
ksuosstats global area                       124216         13          0         13
cache buffer handles                         115915          1          0          1
sequence cache                                37261          6          0          7
resmgr:actses change state                    12454          1          0          1
qmn task queue latch                         179166          8          0          8

希望以上描述可以更清晰地了解Latch是如何获得的,总结一下,在v$latch中,
1. MISSES=0: 表示请求以后就立刻获得了latch。
2. MISSES>0 and SLEEPS=0:表示请求以后没有获得latch,但是通过自旋获得了latch。
3. MISSES>0 and SLEEPS>0:表示请求以后没有获得latch,并且通过2000次自旋也没有获得latch,从而进入了Sleep;或者根本没有自旋就直接进入了Sleep。