A very good post on ASH.

ASH stands for "active session history" and it's official introduction was in Oracle 10g. Oracle 10g introduced ASH and Oracle 11 builds upon that foundation. ASH  is a radically new way to gather performance data. “Radical?” You might ask. Yes, “radical” because ASH only takes samples of data once a second and what happens between samples is lost. The lost data bothers many at first but this unease quickly passes when the power of ASH is understood. ASH provides information necessary to solve some of the toughest performance problems. Before ASH this information was often too difficult and too expensive to get. Previous performance gathering techniques such as STATSPACK (and continued with the even more expensive AWR whose report is almost the same as STATSPACK) lacked the information to solve many performance bottlenecks. Session tracing provides much of the same information as ASH but is much more costly and has to be set up before  a problem arises, proving to be impractical in many situations. Starting in Oracle 10g, ASH is always running, sampling every second, and saved for a week on disk (configurable), thus providing the data need to identify and solve a problem that may have only lasted seconds and days ago.

 

ASH is way of sampling the state of sessions connected to an Oracle database in order to monitory database load as well as drill down into any performance issues that may arise. ASH is a technology that can be applied to any system with connected users such as another database like SQL Server or an operating system or even applications and application servers. Oracle is the first system that I know of using ASH to collect performance data. ASH by default on an Oracle database, samples once every second and logs some 30 to 60 (depending on version) pieces of information on any session that is active at the time of sampling.  One hurtle to accepting ASH as a model had been the question “how fast do we have to sample to get worth while data”. There has been a tendency (I admit having felt this) to want to sample super fast like 10-100 times a second (easily possible with a C program) but experience has shown that  most monitoring and problem resolution can be easily accomplished with 1 second sampling. Higher rate of sampling serve only for rare cases that are better left to tracing. For 99.9% of the time, sampling once a second is sufficient to both show clearly the load on the system as well as provide detailed information on system activity that would otherwise be too difficult or prohibitively expensive to collect (due to the load caused by the data collection itself).

ASH is the collection of active session stated sampled every second. An active session is any session that has made a call to the database.

 

The commitment that Oracle took to ASH required a break from the compulsive quest to gather all the statistics possible at a 100% accuracy which was a futile and limiting strategy. By letting go the drive to collect everything all the time accuratly,  Oracle was able to collect more information, more powerfully and with less over head. How can less be more? ASH took an understanding that the most powerful performance data can be collected not by collecting every thing but by collecting the most important information in a particular manor.

Instead of collecting the exact statistics, ASH is a statistical approximation to the statistic counters. ASH samples every second the session states of all active sessions as well as the SQL the session is executing. This sampling produces a statistical approximation that is cheaper to collect and the multidimensional data allowing new and previously impossible diagnostics.

 

Intractable Performance Data Collection Problem

Previous to ASH, Oracle performance collections tried to collect as much statistics as often as possible. 

This produced a couple of problems

 

    1. Heisenberg  affect 

    2. Overwhelming amount of data

 

For example, database tools tried to collect statistics on all the Sessions, SQL and Objects in the database.

Session information came from v$session.

SQL information came fro v$sql

Object information came from v$segstat (as of Oracle 9i, before 9i it wasn't available)

The collection of this information amounted to massive amounts of work. For example on a system with 150 sessions the number of values to collect would be  150 sessions x (800 wait events + 200 statitics) = 150,000 values to collect every collection ! That's just session information. For SQL, there could be tens of thousands and for each statement we might want to collect a couple dozen statistics. Same for objects - there could be 1000s of objects and for each we'd want to collect a dozen of statistics. The problem quickly becomes intractable. 

    There are optimizations of the collection that allowed some people to doggedly try and collect these kind of statistics. For example for Sessions, SQL and Objects we could filter out any statistics that were zero but for any statistics that wasn't zero we'd have collect it because we wouldn't know if it had changed since we last collected it. For sessions, Oracle does have a counter that tells whether the session has been active since we last collected but SQL and Objects don't have any such counter

 

Sessions

# sessions x (# wait events + statistics)

Example (150 x (800+200) = 150,000 )

SQL

v$sql

Could be 10000s

Takes out latches that compete with other sql executions

Objects

V$segstat 9i+

Could be 1000s of objects

How about other things like v$filestat, etc etc?

    . 

 

The solution? Every second query v$session which is an inexpesive view onto the actual C structures in Oracle shared memory. Only collect information for sessions that are active at the time of collection. Collecting only active sessions is a natural filter for everything we want to filter. This filters out not only unwanted sessions, but also serves as a guide to the SQL,Object and Files we also want to collect information on. We gather not only session information and state, but also gather what SQL they were executing, files and objects they were accessing, honing in directly to the information of most interest to us.

 

ASH:

Intelligently Collects Data

Samples once a second 

Collects active sessions only

Collects the SQL being executed by the session and related information such as objects accessed, files read from etc

More activity,  more data collected 

Less activity, less data collected

Old methods: 

collected everything

Obfuscated the problem, too many statistics too late

Costly

Too  Granular – once an hour ?! Give me a break

 

Sample Every Second

 

Knowing everything – impossible and overwhelming

Knowing enough – possible and manageable 


Sampling is like taking a motion picuture. We miss what happens between pictures but we get enough to know exactly what happened.

 



 

In the above diagram, the vertical lines represent the instant samples are take. Samples are taken once a second, thus for long running queries, over a second, we definitely capture the information. For short queries that are run often, we might miss a lot but we will capture a lot. For short queries that are rarely run, we will miss most of them. This kind of capture filters out queries that have little consequence on database load and focuses in on those queries that are important and put load on the database either because they are resource intensive or because they are run so often that they have a cumulative impact on resources.

 

If it happens a lot or for long ... it will be captured by ASH.

 

Wait events can be classified into 4 major groups

  1. Idle
  2. CPU
  3. IO
  4. Waits

On Oracle databases the classification is easy thanks to a table called V$EVENT_NAME which has a filed "WAIT_CLASS" that tells the kind of wait. 

 

Idle Waits

One problem with Oracle's wait interface when it was introduced in version 7 was that there was no documentation on the wait events and to make matters worse, many of the wait events were "idle", ie the meant that the processes had no work to do and were just waiting. For example if I run SQL*PLUS  but don't actually run any queries, then my session in the database will report that it's waiting for "SQL*Net message to client", meaning the session is ready and waiting to execute queries but I'm not giving it any. Once I submit a query then my state would change to either running on the CPU or some actual non-idle wait event like waiting for IO. But once my query finishes executing and the results are given back to the user in SQL*Plus then the session state in the database goes back to "SQL*Net message to client". The  wait event "SQL*Net message to client" is only one of many idle wait events that don't signify bottlenecks but if I don't know they are idle events, then it might look like my database has huge bottlenecks.  This confusion between real wait events and idle wait events and the lack of documentation slowed the adoption of the wait interface by DBAs and performance analysts. Luckily now it's easy to get the list of idle wait events and create a list of events to ignore with the query:

 

select name 

from v$event_name 

where wait_class='Idle';

             58 Rows

 

If on Oracle 9i or below, you can install statspack which has a table STATS$IDLE_EVENT that lists the idle events. These are events we can ignore when looking at overall database load. They could be relevant when looking at one session. For example, if a session is suppose to be running and we see lots of idle waits, its a signal that the application is inefficiently using the database. For example if the application is inserting 1000s of rows, but inserting one at a time, then a lot of time will be spent on communication between the application and the database session. In this case we will see the session spending a lot of time waiting on idle events when we'd expect it to be on CPU. The solution in that case would be to use batch processing. For example

 

Batching vs Single row operations

 

Single row operations, lots of communication , slowest

-- slowest : single row inserts with commit

insert into foo values ...;

insert into foo values ...;

insert into foo values ...;

insert into foo values ...;

 

          Send all the info over the wire to the database, one communication

-- For Loop

FOR i IN 1..i LOOP  

     INSERT INTO foo VALUES (id(i), data(i));

END LOOP;

COMMIT;

 

          Send all the info over the wire to the database, one communication, bulk insert

-- FORALL

FORALL i IN 1..i  

     INSERT INTO foo VALUES (id(i), data(i));

COMMIT;

 

see http://www.di.unipi.it/~ghelli/didattica/bdl/B19306_01/appdev.102/b14261/tuning.htm#i48876

CPU

CPU is a special case of "wait events". There is no wait event called "CPU" and when we are on CPU we aren't considered to be waiting but actually working. Working is considered a good thing (assuming the work is worth getting done). We might or might not be doing efficient work but that's a different discussion. CPU is one state that a sessions can spend it's time in though, so the CPU state belong in the list of "wait events" or better put "session states". CPU is pivotal in analysis of performance because the relative importance of time waited is all relative to how much time we spent on the CPU. If we spent little time both on CPU and wait time then we weren't doing much. If we spent a lot of time on CPU and little on wait time, then the waits don't matter but if we spent a lot of time waiting and little on CPU then we have an opportunity to improve throughput and response time.

How do we know if a session is on CPU? Oracle doesn't report any such session state directly but it does give us enough information to deduce it. In V$SESSION (or V$SESSION_WAIT before 10g) these fields let us know

 

    

wait_time !=0 and status='ACTIVE'

 

 Both of these fields are in V$SESSION starting in 10g. Before 10g V$SESSION_WAIT has to be joined to V$SESSION to get both of these fields.

IO

IO is a wait but it is a wait that all databases have to so at some point in time. Data has to be read of disk and reading off of disk causes IO wait time. Whether IO wait time is acceptable or not really depends on the application but we can make some general observations such as an optimize disk subsystem should be able to render reads in 10ms. If not and the system spends a lot of time waiting for IO then there is the opportunity to improve throughput. IO waits break down into groups such as IO done by sorts that overflow memory buffers and a written to disk in the temporary tables and read out again. If we see this happening we can investigate increasing memory sort area sizes. Finally we can check the db cache advice and see if there would be any benefit to change the buffer cache size. Once these areas have been checked, it really comes down to investigating the SQL and seeing if they can be optimized either through change the SQL or adding structures such as indexes or if the application logic or architecture can be optimized. 

 

select name from V$EVENT_NAME where WAIT_CLASS=‘User I/O'

 

WAITS

Finally pure waits. These are the waits that we should be able to eliminate from the system theoretically. The one exception to that might be "log file sync" which happens at commit time but can be minimized by having fast log file devices even going to solid state and limiting the commit frequency.

In general if we see other waits and they are important relative to the amount of CPU time spent then we have a clear opportunity for performance tuning. 

Waits are classified by WAIT_CLASS

 

Select wait_class, count(*)  from V$EVENT_NAME where WAIT_CLASS not in ('Idle','User I/O') group by WAIT_CLASS order by WAIT_CLASS;

 

WAIT_CLASS                 COUNT(*)

------------------------ ----------

Administrative                   46

Application                      12

Cluster                          47

Commit                            1

Concurrency                      25

Configuration                    23

Network                          27

Other                           590

Scheduler                         2

System I/O                       24

 

Over 800 waits, though almost 75% of the are "Other", ie they shouldn't happen in normal circumstances. 

 

 

ASH

 

Not only does Oracle collect the active sessions, their session state and they SQL they are executing but Oracle collects a lot more information and stores it in a table V$ACTIVE_SESSION_HISTORY

 

 

SQL>  v$active_session_history

 Name                                      Null?    Type

 ----------------------------------------- -------- ----------------------------

 SAMPLE_ID                                          NUMBER

 SAMPLE_TIME                                        TIMESTAMP(3)

 SESSION_ID                                         NUMBER

 SESSION_SERIAL#                                    NUMBER

 USER_ID                                            NUMBER

 SQL_ID                                             VARCHAR2(13)

 SQL_CHILD_NUMBER                                   NUMBER

 SQL_PLAN_HASH_VALUE                                NUMBER

 SQL_OPCODE                                         NUMBER

 SERVICE_HASH                                       NUMBER

 SESSION_TYPE                                       VARCHAR2(10)

 SESSION_STATE                                      VARCHAR2(7)

 QC_SESSION_ID                                      NUMBER

 QC_INSTANCE_ID                                     NUMBER

 EVENT                                              VARCHAR2(64)

 EVENT_ID                                           NUMBER

 EVENT#                                             NUMBER

 SEQ#                                               NUMBER

 P1                                                 NUMBER

 P2                                                 NUMBER

 P3                                                 NUMBER

 WAIT_TIME                                          NUMBER

 TIME_WAITED                                        NUMBER

 CURRENT_OBJ#                                       NUMBER

 CURRENT_FILE#                                      NUMBER

 CURRENT_BLOCK#                                     NUMBER

 PROGRAM                                            VARCHAR2(48)

 MODULE                                             VARCHAR2(48)

 ACTION                                             VARCHAR2(32)

 CLIENT_ID                                          VARCHAR2(64)

 

Looks like a lot of fields! Let's break it down into bite sizes logical pieces:

 

 

 

Of these fields the basic information is

 

 

 

But all of the fields of ASH allow large number of options for aggregation and analysis such as

 

 

 

and starting in 10.2.0.3 Oracle as Package and Procedure so we can find the top Package and Procedure by all the resources listed above such as CPU, WAIT, IO or TIME.

ASH is multidimensional data that can be group in many ways.

 

 

 

Who is creating the load:

-- session identifiers :                              
SESSION_ID                                            
SESSION_SERIAL#  (identify SID reuse)                 
SESSION_TYPE     (FOREGROUND,BACKGROUND)              
-- grouping options :                                 
USER_ID          (SYS, SYSTEM, SCOTT etc)             
SERVICE_HASH     (OE,GL,HR)                           
MODULE.ACTION    (PLSQL tagging)                      
CLIENT_ID        (identifying users in session pool)  
PROGRAM          (SQL, JDBC, Forms etc)               

 

SQL Identfiers

SQL_ID                                                
QC_SESSION_ID    (Query Coordinator)                  
QC_INSTANCE_ID   (RAC)                                

 

Wait Information

EVENT                                                 
P1                                                    
P2                                                    
P3                                                    

 

Object information (IO, buffer busy wait, lock enqueue TX waits only)

CURRENT_OBJ#                                          
CURRENT_FILE#                                         
CURRENT_BLOCK#                                        

 

Top CPU consuming Session in last 5 minutes? 

 

Select

              session_id,

              count(*)

from

              v$active_session_history

where

              session_state= ‘ON CPU‘ and

              SAMPLE_TIME > sysdate – (5/(24*60))

group by

              session_id

order by

               count(*) desc;

 

 

SESSION_ID   COUNT(*)

---------- ----------

       257        299

       263         62

       256         32

       264          9

       277          3

       258          1

 

Top Waiting Session  in last 5 minutes

 

 

           Select

                  session_id,

                  count(*)

 from

                  v$active_session_history

 where

                  session_state=WAITING’  and

                  SAMPLE_TIME >  SYSDATE - (5/(24*60))

 group by

                  session_id

 order by

                    count(*) desc;

 

 

     SESSION_ID   COUNT(*)

---------- ----------

       272        224

       254          8

       249          5

       276          5

       277          4

  270          1

 

 

Top SQL by CPU usage, wait time and IO time

 

            select

     ash.SQL_ID ,

     sum(decode(ash.session_state,'ON CPU',1,0))     "CPU",

     sum(decode(ash.session_state,'WAITING',1,0))    -

     sum(decode(ash.session_state,'WAITING', decode(en.wait_class, 'User I/O',1,0),0))    "WAIT" ,

     sum(decode(ash.session_state,'WAITING', decode(en.wait_class, 'User I/O',1,0),0))    "IO" ,

     sum(decode(ash.session_state,'ON CPU',1,1))     "TOTAL"

from v$active_session_history ash,

         v$event_name en

where SQL_ID is not NULL  and en.event#=ash.event#

group by sql_id

order by sum(decode(session_state,'ON CPU',1,1))   desc

 

    SQL_ID               CPU    WAITING         IO      TOTAL

------------- ---------- ---------- ---------- ----------

4c1xvq9ufwcjc      23386          0          0      23386

6wjw6rz5uvbp3         99          0         23        122

968dm8hr9qd03         97          0         22        119

938jp5gasmrah         90          0         25        115

cv8xnv81kf582         42          0          9         51

6p9bzu19v965k         21          0          0         21

5zu8pxnun66bu         15          0          0         15

db2jr13nup72v          9          0          0          9

7ks5gnj38hghv          8          0          0          8

 

 

Top SESSION by CPU usage, wait time and IO time

 

select

     ash.session_id,

     ash.session_serial#,

     ash.user_id,

     ash.program,

     sum(decode(ash.session_state,'ON CPU',1,0))     "CPU",

     sum(decode(ash.session_state,'WAITING',1,0))    -

     sum(decode(ash.session_state,'WAITING',

        decode(en.wait_class,'User I/O',1, 0 ), 0))    "WAITING" ,

     sum(decode(ash.session_state,'WAITING',

        decode(en.wait_class,'User I/O',1, 0 ), 0))    "IO" ,

     sum(decode(session_state,'ON CPU',1,1))     "TOTAL"

from v$active_session_history ash,

        v$event_name en

where en.event# = ash.event#

group by session_id,user_id,session_serial#,program

order by sum(decode(session_state,'ON CPU',1,1))

 

 

SESSION_ID SERIAL#    USER_ID PROGRAM                      CPU    WAITING         IO

---------- ------- ---------- ------------------------- ------- ---------- ----------

       247   61970          1 sqlplus                     11698          0          0

       277       1          0 oracle@labsfrh903 (LGWR)       14         21          0

       276       1          0 oracle@labsfrh903 (CKPT)       19         10          0

       278       1          0 oracle@labsfrh903 (DBW0)       29          0          0

       280       1          0 oracle@labsfrh903 (PMON)       19          0          0

       254   22617          5 Executor.exe                   13          0          3

       255   12877          5 Executor.exe                   11          0          5

       257   33729          5 Executor.exe                   15          0          1

       255   13417          5 Executor.exe                   14          0          2

 

 

Top SQL with Username and connection status

 

 

select

        decode(nvl(to_char(s.sid),-1),-1,'DISCONNECTED','CONNECTED')

                                                            "STATUS",

        topsession.session_id             "SESSION_ID",

        u.name                                         "NAME",

        topsession.program                  "PROGRAM",

        max(topsession.CPU)               "CPU",

        max(topsession.WAITING)       "WAITING",

        max(topsession.IO)                   "IO",

        max(topsession.TOTAL)            "TOTAL"

        from {previous query}   )        topsession,

                                                        v$session s,

                                                        user$ u

   where

                    u.user# =topsession.user_id and

                   /* outer join to v$session because the session might be disconnected */

                   topsession.session_id         = s.sid         (+) and

                   topsession.session_serial# = s.serial#   (+)

   group by  topsession.session_id, topsession.session_serial#, topsession.user_id,

                   topsession.program, s.username,s.sid,s.paddr,u.name

   order by max(topsession.TOTAL) desc

 

 

    STATUS          SESSION_ID NAME       PROGRAM                     CPU    WAITING   IO

--------------- ---------- ---------- ------------------------- ----- ---------- ----

CONNECTED              247 CPU_Monger ChMgr304.exe              11704          0    0

CONNECTED              277 SYS        oracle@labsfrh903 (LGWR)     14         19    0

CONNECTED              278 SYS        oracle@labsfrh903 (DBW0)     29          0    0

CONNECTED              276 SYS        oracle@labsfrh903 (CKPT)     18          9    0

CONNECTED              280 SYS        oracle@labsfrh903 (PMON)     20          0    0

DISCONNECTED           255 SYSTEM     Executor.exe                 11          4    5

DISCONNECTED           257 SYSTEM     Executor.exe                 13          0    3

DISCONNECTED           255 SYSTEM     Executor.exe                 14          0    2

DISCONNECTED           257 SYSTEM     Executor.exe                 13          0    3

 

 

 

Note on  Active or Waiting

 

SESSION_STATE

            Waiting, on CPU

            Based on WAIT_TIME

WAIT_TIME (v$session, v$session_wait, v$ash)

              0   => waiting

            >0   => CPU        (value is time of last wait)

TIME_WAITED 

            Actual time waited for event

            0 until wait finishes 

            Fix up values (no one else can do this)

 

 

 

 

ASH family of tables 

 

 

 

a

a

 

 

Circular Buffer - 1M to 128M  (~2% of SGA)

Flushed every hour to disk or when buffer 2/3 full (it protects itself so you can relax)

Avg row around 150bytes

3600 secs in an hour

~ ½ Meg per Active Session per hour

That’s generally over an hour of ASH

 

Dumping ASH to flat file

oradebug dump ashdump 5

Alter session set events ‘immediate trace name ashdump level 5’;

level 5 =  # of minutes

loader file rdbms/demo/ashldr.ctl

 

statistics_level  = Typical (default)

 

PARAMETER           SESSION_VALUE   INSTANCE_VAL

----------------------- ---------- ------------

_ash_sampling_interval       1000          1000

   milliseconds

_ash_size                 1048618       1048618

   ASH buffer size

_ash_enable                 TRUE           TRUE

   Turn on/off ASH sampling, flushing and the V$ views on ASH

_ash_disk_write_enable      TRUE           TRUE

 Flush to disk 

_ash_disk_filter_ratio        10             10

 write 1 in 10 points

_ash_sample_all            FALSE           FALSE

 Sample including idle waits

10.2 added fields to ASH

 

Blocking Session !

BLOCKING_SESSION               

BLOCKING_SESSION_STATUS        

BLOCKING_SESSION_SERIAL#       

 Parameter Names

P1TEXT , P2TEXT, P3TEXT                         

Wait Grouping

WAIT_CLASS                     

WAIT_CLASS_ID 

Transactions

XID

Cursor sharing 

FORCE_MATCHING_SIGNATURE

 

10.2.0.2 added

PLSQL_ENTRY_OBJECT_ID          

PLSQL_ENTRY_SUBPROGRAM_ID      

PLSQL_OBJECT_ID                

PLSQL_SUBPROGRAM_ID

connect to ALL_PROCEDURES with

 

where object_id = plsql_object_id  

and subprogram_id = plsql_subprogram_id 

 

11.1.0 added

Identifying SQL Execution - Is this same execution as last sample? 

 SQL_EXEC_ID

 SQL_EXEC_START

SQL Execution Row Source - Identifies current row source within plan

 SQL_PLAN_LINE_ID

 SQL_PLAN_OPERATION

 SQL_PLAN_OPTIONS

RAC block transfers - Remote instance id for Cache transfers, Which instance sourced requested block? 

 REMOTE_INSTANCE#

Recursive SQL

TOP_LEVEL_SQL_ID

TOP_LEVEL_SQL_OPCODE

CPU breakdown - Operation bit vector , Capture non-timed operations

 IN_CONNECTION_MGMT

 IN_PARSE

 IN_HARD_PARSE

 IN_SQL_EXECUTION

 IN_PLSQL_EXECUTION

 IN_PLSQL_RPC

 IN_PLSQL_COMPILATION

 IN_JAVA_EXECUTION

 IN_BIND

 IN_CURSOR_CLOSE

ETC

 CURRENT_ROW# 

 EVENT# 

 QC_SESSION_SERIAL#

 CONSUMER_GROUP_ID

 FLAGS

 

How much data does ASH Collect ?

1 CPU means max 1 Avg Active Session unless there is a bottleneck

Big site examples:

Oracle 4 way RAC internal apps

10,000 connected, 200 active

One Site 

3000 connected, 30 Active

Site 

12,000 connected, 100 active

a

 

 

Ash Across Versions

 

ASH across the versions

ASH is now at 93 fields in 11gR2, starting from an original 30 in 10gR1

Here is a spread sheet across 10.1.0, 10.2.0.1, 10.2.0.3,11.1, 11.2

http://spreadsheets.google.com/pub?key=t7c5YZ1hD_I25jLa2D6DdLg&output=html

for 11gR2 documentation see:

 http://download.oracle.com/docs/cd/E11882_01/server.112/e10820/dynviews_1007.htm#I1030299

 

      10.1         10.2          10.2.0.3      11.1           11.2

 

Data Mining Scripts

 

aveact.sql - day of data, 1 line per hour

   "+" - represent CPU usage

   "-" - represent wait time

   "2" in the GRAPH is the number of CPUS on this machine

   GRAPH is a graphical representation of AVEACT (AAS)

TM                 NPTS  AVEACT GRAPH                   CPU WAITS

---------------- ------ ------- ---------------------- ---- -----

06-AUG  13:00:00    270     .33 +-        2              29    59

06-AUG  14:00:00   1040    2.24 ++--------2---          341  1984

06-AUG  15:00:00    623    6.67 ++++------2----------   438  3718

06-AUG  16:00:00   1088    2.59 ++--------2----         335  2486

06-AUG  17:00:00   1104    1.26 ++-----   2             349  1043

06-AUG  18:00:00   1093    1.38 +++----   2             663   842

06-AUG  19:00:00   1012    1.74 ++------- 2             373  1388

06-AUG  20:00:00   1131     .99 +----     2             304   820

06-AUG  21:00:00   1111    1.22 ++-----   2             344  1012

06-AUG  22:00:00   1010    1.66 ++------  2             414  1259

06-AUG  23:00:00   1120    1.08 +----     2             298   913

07-AUG  00:00:00   1024     .83 +---      2             273   576

07-AUG  01:00:00   1006    1.74 ++------- 2             319  1428

07-AUG  02:00:00   1090    2.47 ++--------2----         347  2345

07-AUG  03:00:00    687    6.59 +++-------2----------   382  4142

07-AUG  04:00:00   1004    1.95 ++++++--- 2            1299   659

07-AUG  05:00:00   1104    3.08 +++++-----2------      1170  2226

07-AUG  06:00:00   1122    1.91 +++++++-- 2            1582   558

07-AUG  07:00:00   1115    1.06 +++---    2             559   618

07-AUG  08:00:00   1140     .81 ++--      2             403   519

07-AUG  09:00:00   1128     .88 ++---     2             386   601

aveactn.sql - - day of data, 1 line per hour, show the top to waits as well as graph

 

TO_CHAR(STA    SAMPLES  AAS1 FIRST            AAS2 SECOND          GRAPH

----------- ---------- ----- --------------- ----- --------------- ------------------------------

23 10:00:00        647   .01 db file sequent   .01 db file scatter                     4

23 11:00:00       2773   .02 CPU               .01 buffer busy wai                     4

23 12:00:00       3029   .00 CPU               .00 db file paralle                     4

23 01:00:00       2761   .00 SQL*Net break/r   .00 control file se                     4

23 02:00:00       2258   .00 CPU               .00 log file sync                       4

23 03:00:00       1651   .03 buffer busy wai   .01 CPU     

 

aveactf.sql- same as above but finer frequency ( 1 hour of data, line for every minute) 

aveactnf.sql - same as above but finer frequency  ( 1 hour of data, line for every minute) 

 

 

<think>我们有两个视图:v$session 和 v$active_session_history。用户想要在查询这些视图时同时显示SQL的文本内容。 在Oracle中,SQL文本存储在v$sql或v$sqlarea等视图中。我们可以通过SQL_ID(在v$session和v$active_session_history中都有)来关联这些视图,从而获取SQL文本。 注意:v$active_session_history中存储的是历史活动会话信息,而v$session是当前会话信息。 对于v$session,我们可以这样写: SELECT s.sid, s.serial#, s.username, s.machine, s.program, s.module, s.client_info, q.sql_text FROM v$session s LEFT JOIN v$sql q ON s.sql_id = q.sql_id WHERE s.status = 'ACTIVE'; 但是注意,一个SQL_ID可能对应多个子游标(child cursor),但通常我们取其中一个即可(比如通过sql_id和child_number),或者使用v$sqlarea(它按sql_id聚合,但只显示一个子游标的sql_text)。不过,v$sqlarea中sql_text可能是截断的(只显示前1000字符),而v$sql中sql_fulltext是完整的(CLOB类型,但显示时可能受限于工具)。 另外,v$active_session_history中,每个活动会话每秒采样一次,可能同一个会话在多次采样中执行不同的SQL,所以我们需要根据SQL_ID来关联。 对于v$active_session_history的查询: SELECT ash.sample_id, ash.sample_time, ash.session_id, ash.session_serial#, ash.sql_id, ash.sql_exec_id, ash.event, ash.wait_class, q.sql_text FROM v$active_session_history ash LEFT JOIN v$sql q ON ash.sql_id = q.sql_id WHERE ash.sample_time BETWEEN ... AND ...; 但是,v$active_session_history中可能包含历史数据,而v$sql中可能已经没有对应的SQL(因为SQL游标被刷出共享池)。为了获取更久远的SQL文本,我们可以关联dba_hist_sqltext(需要AWR许可,并且已经做过快照)。 因此,如果我们想要查询v$active_session_history并且显示SQL文本,有两种情况: 1. 如果SQL还在共享池中(v$sql中还存在),则从v$sql中获取。 2. 如果SQL已经不在共享池中,则从dba_hist_sqltext中获取(前提是AWR快照已经捕获)。 但是,由于用户没有特别说明历史数据,我们先提供当前共享池中能关联到的SQL文本。 另外,注意v$sql中的sql_text是前1000个字符,而sql_fulltext是完整的SQL文本(CLOB)。我们可以使用DBMS_LOB.SUBSTR来截取,或者根据工具支持直接显示。 以下提供两个查询示例: 1. 查询v$session并显示SQL文本(当前正在执行的SQL): SELECT s.sid, s.serial#, s.username, s.machine, s.program, s.module, s.client_info, s.sql_id, q.sql_text, -- 前1000个字符 DBMS_LOB.SUBSTR(q.sql_fulltext, 4000, 1) AS sql_fulltext -- 显示最多4000字符 FROM v$session s LEFT JOIN v$sql q ON s.sql_id = q.sql_id WHERE s.status = 'ACTIVE'; 2. 查询v$active_session_history并显示SQL文本(注意:v$active_session_history中的SQL_ID可能为null,表示当时没有执行SQL): SELECT ash.sample_id, ash.sample_time, ash.session_id, ash.session_serial#, ash.sql_id, ash.sql_exec_id, ash.event, ash.wait_class, q.sql_text, DBMS_LOB.SUBSTR(q.sql_fulltext, 4000, 1) AS sql_fulltext FROM v$active_session_history ash LEFT JOIN v$sql q ON ash.sql_id = q.sql_id WHERE ash.sample_time > SYSDATE - INTERVAL '1' HOUR -- 最近一小时 ORDER BY ash.sample_time DESC; 但是,如果v$sql中已经没有了,我们可以尝试关联dba_hist_sqltext(需要AWR许可): SELECT ash.sample_id, ash.sample_time, ash.session_id, ash.session_serial#, ash.sql_id, ash.sql_exec_id, ash.event, ash.wait_class, COALESCE(q.sql_text, h.sql_text) AS sql_text FROM v$active_session_history ash LEFT JOIN v$sql q ON ash.sql_id = q.sql_id LEFT JOIN dba_hist_sqltext h ON ash.sql_id = h.sql_id WHERE ash.sample_time > SYSDATE - INTERVAL '1' HOUR ORDER BY ash.sample_time DESC; 注意:dba_hist_sqltext中的sql_text是完整的SQL文本(VARCHAR2类型,最多4000字符),如果SQL文本超过4000字符,则会被截断。而v$sql中的sql_fulltext是CLOB,可以显示更长的文本(但我们在查询时通过DBMS_LOB.SUBSTR转换为4000字符)。 另外,如果用户没有AWR许可,则不能使用dba_hist_sqltext。 因此,我们给出一个通用的,只使用v$sql的查询。 最后,注意权限:用户需要被授予SELECT_CATALOG_ROLE,或者直接授予对v$session, v$sql, v$active_session_history, dba_hist_sqltext的查询权限。 由于用户的问题中提到了“现有的Oracle性能视图查询”,我们假设用户已经有查询这些视图的权限。 现在,根据用户提供的引用,我们知道v$active_session_history是内存中的,重启会消失,而dba_hist_active_sess_history是持久化的。但是,我们这里只需要关联SQL文本,所以用dba_hist_sqltext就可以。 总结:在查询v$session和v$active_session_history时,通过关联v$sql或dba_hist_sqltext来获取SQL文本。</think>### Oracle 查询添加 SQL 文本内容的方法 在 Oracle 中,可以通过关联 `v$sql` 或 `dba_hist_sqltext` 视图来获取 SQL 文本内容。以下是具体实现方法: #### 1. 查询 `v$active_session_history` + SQL 文本 ```sql SELECT ash.sample_id, ash.sample_time, ash.session_id, ash.sql_id, ash.event, ash.wait_class, ash.machine AS "客户端主机", ash.program AS "客户端程序", s.sql_text AS "SQL文本", DBMS_LOB.SUBSTR(s.sql_fulltext, 4000, 1) AS "完整SQL文本" FROM v$active_session_history ash LEFT JOIN v$sql s ON ash.sql_id = s.sql_id WHERE ash.sample_time > SYSDATE - INTERVAL '1' HOUR AND ash.session_state = 'ON CPU' -- 过滤活动会话 ORDER BY ash.sample_time DESC; ``` #### 2. 查询 `v$session` + SQL 文本(实时会话) ```sql SELECT s.sid, s.serial#, s.username, s.machine AS "客户端主机", s.program AS "客户端程序", s.module AS "应用模块", q.sql_text AS "当前SQL文本", DBMS_LOB.SUBSTR(q.sql_fulltext, 4000, 1) AS "完整SQL文本" FROM v$session s LEFT JOIN v$sql q ON s.sql_id = q.sql_id WHERE s.status = 'ACTIVE'; ``` #### 3. 历史 SQL 文本查询(需 AWR 许可) ```sql SELECT ash.sample_time, ash.session_id, ash.sql_id, ash.machine, t.sql_text AS "历史SQL文本" FROM dba_hist_active_sess_history ash JOIN dba_hist_sqltext t ON ash.sql_id = t.sql_id WHERE ash.sample_time BETWEEN TO_DATE('2023-01-01','YYYY-MM-DD') AND TO_DATE('2023-01-02','YYYY-MM-DD'); ``` ### 关键说明: 1. **SQL文本获取原理** - 通过 `sql_id` 关联 `v$sql` 或 `dba_hist_sqltext` 视图[^1][^3] - `v$sql.sql_text`:显示前 1000 字符 - `DBMS_LOB.SUBSTR(sql_fulltext)`:显示完整 SQL(CLOB 转 VARCHAR2) 2. **性能优化建议** ```sql -- 创建 SQL_ID 索引加速关联查询 CREATE INDEX idx_sql_id ON v$sql(sql_id); ``` 3. **权限要求**: ```sql GRANT SELECT ON v_$sql TO your_user; GRANT SELECT ON dba_hist_sqltext TO your_user; ``` ### 注意事项: 1. `v$active_session_history` 数据保留约 1 小时(内存中),重启后丢失[^1][^2] 2. `dba_hist_sqltext` 需要 AWR 许可且已启用快照[^2][^3] 3. 超过 1000 字符的 SQL 需使用 `sql_fulltext` 字段 4. 空闲会话(IDLE)不会出现在 ASH 采样中[^4][^5] > **示例输出**: > ![查询结果示例](https://example.com/oracle-ash-sqltext.png) > *显示客户端主机、程序和对应 SQL 文本的查询结果* ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值