DBPedias

Your Database Knowledge Community

oraclenerd

  1. Building an OBIEE Test Lab - Part II

    So it's taking a little longer than I anticipated. That's a good thing (for me anyway). In Part I, I tried to diagram out what my plans were. My drawing was crude, and remains so. Mike Durran left me a link to the drawing below which is found here in the docs.



    Now I'm an ambitious lad, but not that ambitious. This is for fun and amusement, perhaps I'll learn a thing or two along the way.

    So how does this qualify as Part II? Well, I finally created the database. (No, I'm not going RAC like the diagram and docs say. Like I said, I'm not completely nutters.) This is an accomplishment for me as it's been quite some time since I've built anything, close to a year. So I'm celebrating by writing.
    Oracle Enterprise Linux 64 bit, 5.8
    2.6.32-300.32.1.el5uek
    Database: 11.2.0.1
    Database host: oracle-db
    Database SID: TESTING
    
    I used OEL 5.8 because that's the latest version I could find that was certified for 11.2.0.1 (straight from OTN). I was unable to find a single document that listed out the supported OSes, but I'm not that adept at searching through MOS yet (LOWER( DBA )). If you know where it is, please link it up.

    This database will serve as the repository home for OBIEE and perhaps something like Identity Manager (OVM, OAM). I'll probably end up using it as a source and target for various projects as well.
  2. Good DBA, Bad DBA, Deadlock

    By Enrique Aviles

    A few days ago a fellow DBA asked me to review an email he received from a developer. In the email, the developer explained his application was affected by database errors and asked us to check the attached file for details. The error was a database deadlock. Attached to the email was the trace file Oracle generates whenever a deadlock occurs in the database. I don’t see deadlocks regularly so I hardly ever need to dissect one of those trace files. The trace file contained the following information:
    Deadlock graph:
                           ---------Blocker(s)--------  ---------Waiter(s)---------
    Resource Name          process session holds waits  process session holds waits
    TX-002b0006-00000968        23     223     X             25      35           X
    TX-002c0007-00000b13        25      35     X             23     223           X
    
    session 223: DID 0001-0017-000163D0     session 35: DID 0001-0019-00002809
    session 35: DID 0001-0019-00002809      session 223: DID 0001-0017-000163D0
    
    Rows waited on:
      Session 223: obj - rowid = 0001FBA6 - AAAfumAAFAAAWikAAA
      (dictionary objn - 129958, file - 5, block - 92324, slot - 0)
      Session 35: obj - rowid = 0001FBA6 - AAAfumAAFAAAWikAAB
      (dictionary objn - 129958, file - 5, block - 92324, slot - 1)
    Session 223 holds an exclusive lock on a row and session 35 holds another exclusive lock on a different row. Session 35 wants to lock session 235 row and vice versa. This clearly shows there is a deadlock. Immediately following this section the SQLs involved in the deadlock are shown in the trace file. I was expecting to see two different queries but the current session and the “other” session executed exactly the same SQL:
    UPDATE PERSON_TAB SET PERSON_ID=:1, 
      NAME=:2, FIRST_NAME=:3, 
      MIDDLE_NAME=:4, 
      LAST_NAME=:5, 
      DATE_OF_BIRTH=:6, 
      PHONE_NUMBER=:7, 
      ALT_PHONE_NUMBER=:8, 
      FAX_NUMBER=:9, 
      E_MAIL=:10 
    where DATA_SOURCE_ID=:11
    The fact that the same UPDATE was executed by both sessions against the same table confused me for a moment. For some reason I wanted to see two different tables but found the same table in both UPDATEs. I started thinking one session updated a row and another session wanted to update the same row. On that scenario the second session would just wait for the first session to either commit or rollback the update. Once that happens the exclusive lock on the row is released and the UPDATE from the second session goes through. How can that cause a deadlock? As you can tell, I didn’t read the trace file close enough. The rowids above are different so both sessions were trying to update different rows. Once again, I rushed to faulty reasoning thinking two sessions updating two different rows should not cause a deadlock. Clearly, Oracle is able to handle two sessions updating two different rows with ease. They are completely independent transactions so there shouldn’t be a deadlock. Remember, I don’t analyze deadlock trace files on a daily basis so that’s my defense for not being able to immediately explain what caused the deadlock. After a few moments trying to imagine what could have caused the deadlock I was able to see the full picture. The first session updates row 1, the second session updates row 2. The first session tries to update row 2 and the second session tries to update row 1. This sequence causes a deadlock. In order to validate my reasoning I opened two SQL*Plus sessions and ran the following:
    On session #1:
    SQL> CREATE TABLE T (N NUMBER);
    SQL> INSERT INTO T VALUES (1);
    SQL> INSERT INTO T VALUES (2);
    SQL> COMMIT;
    SQL> UPDATE T SET N = 10 WHERE N = 1;
    On session #2:
    SQL> UPDATE T SET N = 20 WHERE N = 2;
    On session #1:
    SQL> UPDATE T SET N = 20 WHERE N = 2; (this one blocks because it’s locked by session #2)
    On session #2
    SQL> UPDATE T SET N = 10 WHERE N = 1; (this one causes a deadlock)
    After a few seconds the database reported a deadlock on session #1. As a result, the second update on session #1 was lost. After issuing a commit on both sessions I noticed the table didn’t contain two rows with 1 and 2 but 10 and 20. No updates were lost because both sessions tried to update the table with the same values. The same would happen if the UPDATEs on PERSON_TAB contained the same values on all columns. If PHONE_NUMBER was different on both sessions one of them would be lost as a result of the deadlock. With this information on hand my colleague replied the email with a detailed explanation as to what caused the deadlock and provided the small case scenario to help the developer reproduce the issue. We also supplied the SQL showing the table involved in the deadlock.

    We acted as good DBAs (we think so) because we took the time to examine the trace file, compose a detailed explanation, and supply steps on how to reproduce the issue.

    What would a bad DBA do if faced with the same request? The bad DBA would open the trace file and copy the following section on a reply email:
    The following deadlock is not an ORACLE error. It is a
    deadlock due to user error in the design of an application
    or from issuing incorrect ad-hoc SQL.
    The email would close with a simple “fix your code”.
  3. Pythian Acquires "Dude Who Gets Stuff Done"

    Pythian, the world's leading remote DBA service company, has announced the (non-hostile) acquisition of John Piwowar.

    Wait, Pythian didn't announce it, officially anyway...



    Source



    Source

    Maybe it was John?

    ...Starting today, I begin the "on-boarding" process at Pythian, as a member of one of their ERP teams.
    In a way, it feels as much like starting school as it does a new job. This move represents my biggest career challenge to date, and I
    look forward to learning a ton (and contributing a ton) in the company of a lot of smart, talented people. Since I'm going to be packing
    my brain full of new things over the next 3 weeks, I expect that the only blog activity here will be from pre-scheduled posts, drafts that
    I'd been putting off finishing until recently. Once I'm up to speed on the new system, you'll hopefully be hearing more from me on the
    Pythian blog!

    I think it's obvious from John's post how excited he is. I am excited for him too. John's an awesome dude, sherpa (for me), protector (of me, from myself), and DBA.

    Find John in the following locations:

    - Twitter
    - Blog
    - LinkedIn
    - oraclenerd

    OK, this didn't turn out as funny as I had intended, whatever.

    Great move for both parties. Can't wait to see what John does with the vast resources available to him now.
  4. The &DBA

    Pronounced, Ampersand DBA.

    I'm hearby naming all my future DBAs that meet certain criteria, &DBA.;

    Over the years, at about a million different organizations, I have met many DBAs. Many, at first glance, fit the DBA stereotype; cranky, condescending, arrogant, etc. After further review, many of those traits still apply. Some however turn out to be the opposite; they just put on a game face for the new guy or gal because they've been through this before...probably to be disappointed again that the developer will 1, leave them out of design discussions 2, throw bad SQL over the wall, 3, not use bind variables, ever and 4, well, all the other bad things we developers do.

    The type that I have least encountered are the DBAs who actively seek out and engage developers. Hey, can I help you with that? Hey, you aren't using bind variables, here are the reasons you should. They know that in the long run, the better the developer, the easier their job will be.

    I love that aspect of my job. I like helping others learn to do something better or more efficiently. I like to encourage others to download and install the database. But that's not the point of this post...

    I needed a name for those DBAs who are 1, less qualified than I am to be a DBA (short list, I am under no illusions), 2, are wholly incompetent and 3, are jerks.

    After a recent incident, as relayed by others, the &DBA; was born.

    What does the & mean?

    In SQL*Plus, the & is a special character. If you run scripts you can parameterize them with &COLUMN;_VALUE or something, right?

    That's great for scripts.

    It can go horribly wrong with code. At least the first time you try to load code via SQL*Plus. Here's the original

    CREATE OR REPLACE
    FUNCTION foo RETURN VARCHAR2
    AS
      l_retval VARCHAR2(10);
      l_value VARCHAR2(30) := 'Barnes & Noble';
    BEGIN
      SELECT 'IT WORKS!'
      INTO l_retval
      FROM dual
      WHERE 'Barnes & Noble' = l_value;
    
      RETURN l_retval;
    
    END foo;
    /
    show errors
    and here's what happens when I run it:
    CJUSTICE@NO_CLUE>CREATE OR REPLACE
    FUNCTION foo RETURN VARCHAR2
      2  AS
      3    l_retval VARCHAR2(10);
      4    l_value VARCHAR2(30) := 'Barnes & Noble';
      5  BEGIN
      6    SELECT 'IT WORKS!'
      7    INTO l_retval
      8    FROM dual
      9    WHERE 'Barnes & Noble' = l_value;
     10
     11    RETURN l_retval;
     12
     13  END foo;
     14  /
    Enter value for noble: show errors
    old   3:   l_value VARCHAR2(30) := 'Barnes & Noble';
    new   3:   l_value VARCHAR2(30) := 'Barnes show errors';
    Enter value for noble: testing
    old   8:   WHERE 'Barnes & Noble' = l_value;
    new   8:   WHERE 'Barnes testing' = l_value;
    
    Warning: Function created with compilation errors.
    This is how it is stored in the database:
    FUNCTION foo RETURN VARCHAR2
    AS
      l_retval VARCHAR2(10);
      l_value VARCHAR2(30) := 'Barnes show errors';
    BEGIN
      SELECT 'IT WORKS!'
      INTO l_retval
      FROM dual
      WHERE 'Barnes testing' = l_value;
    
      RETURN l_retval;
    
    END foo;
    
    12 rows selected.
    Yeah, that won't work.

    To fix this, you simply set an attribute/directive? in your SQL*Plus session, SET DEFINE OFF (I believe there is another, but this is the one I use). Like this:
    CJUSTICE@NO_CLUE>SET DEFINE OFF
    CJUSTICE@NO_CLUE>
    CJUSTICE@NO_CLUE>CREATE OR REPLACE
      2  FUNCTION foo RETURN VARCHAR2
      3  AS
      4    l_retval VARCHAR2(10);
      5    l_value VARCHAR2(30) := 'Barnes & Noble';
      6  BEGIN
      7    SELECT 'IT WORKS!'
      8    INTO l_retval
      9    FROM dual
     10    WHERE 'Barnes & Noble' = l_value;
     11
     12    RETURN l_retval;
     13
     14  END foo;
     15  /
    
    Function created.
    
    Elapsed: 00:00:00.22
    CJUSTICE@NO_CLUE>show errors
    No errors.
    CJUSTICE@NO_CLUE>
    CJUSTICE@NO_CLUE>SET DEFINE ON
    All is now well in the world.

    Now this might be vexing on your first couple of weeks on the job, but you quickly pick it up.

    This is where the name comes from...

    SET DEFINE OFF
    &DBA;
    SET DEFINE ON


    said that this was a known Oracle bug.

    Really.
  5. Yet Another Slow Query

    by Enrique Aviles

    As the database performance contact I get to troubleshoot slow queries. Typically when users experience a slow application screen an incident is submitted and the issue ends up on my plate. Recently, I had to investigate a report that was taking a little over 10 minutes to generate results. Although the application is an OLTP system some screens allow users to generate a report that can be sent to the printer. Normally these reports take a few seconds to appear on the screen but this one was way over the application’s SLA requirements.

    Below is a sample query construct that captures the syntax of the actual query that was executed by the application. After examining execution plans and generating extended SQL trace I identified the parts highlighted in red as the ones contributing to the query’s poor response time.
    SELECT T1.COLUMN_1,
           T1.COLUMN_2,
           V1.COLUMN_1,
           V1.COLUMN_2,
           T2.COLUMN_1,
           T2.COLUMN_2,
           V2.COLUMN_1,
           V2.COLUMN_2,
           CV.USAGE,
           .
           .
           .
    24 additional columns
           .
           .
           .
    FROM
           TABLE_1 T1,
           TABLE_2 T2,
           TABLE_3 T3,
           TABLE_4 T4,
           VIEW_1 V1,
           VIEW_2 V2,
    COMPLEX_VIEW CV
           .
           .
    An additional mix of 7 tables and views
           .
           .
    WHERE T1.COLUMN_4 = T2.COLUMN_5
    AND T2.COLUMN_7   = T3.COLUMN8
    .
    .
    .
    AND
    CV.PARAMETER_ID = T3.ID
    AND CV.PART_ID  = T4.ID
    AND CV.LOG_DATE = (
                       SELECT MAX(CV2.LOG_DATE)
                       FROM COMPLEX_VIEW CV2
                       WHERE CV2.PART_ID    = CV.PART_ID
                       AND CV2.PARAMETER_ID = CV.PARAMETER_ID
                      )
    AND T5.ID = 'ABC123'
    The query’s runtime statistics are:
    Elapsed: 00:13:13.01
    
    Statistics
    ----------------------------------------------------------
           4013  recursive calls
           6372  db block gets
       65682217  consistent gets
         858907  physical reads
              0  redo size
           3328  bytes sent via SQL*Net to client
            524  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              3  sorts (memory)
              1  sorts (disk)
              1  rows processed
    The query took more than 13 minutes and over 65 million consistent gets to select one row. This is obviously unacceptable so it is clear why users were not happy with that particular report. What could be causing the query to generate so much work?

    The complex view is composed of twelve tables and 40 lines in the WHERE clause, five of them OR conditions. I noticed that removing the subquery that gets the maximum LOG_DATE from the complex view helped the main query to complete in just a few seconds. Obviously, results were incorrect without the subquery so I had to figure out a way to preserve the logic that gets the maximum LOG_DATE while having the query complete in a matter of seconds.

    Examining the complex view data showed there were no duplicate LOG_DATEs so the MAX aggregate function will always return the absolute maximum LOG_DATE for a given PART_ID/PARAMETER_ID combination. Finding that characteristic in the data led me to consider using a scalar subquery to get the USAGE value from the complex view. In the process I also wanted to select from the complex view in one pass so I decided to use the ROW_NUMBER analytic function to get the maximum LOG_DATE and eliminate the need for a self-join via a correlated subquery. Having devised that plan, I executed the following query to test what would become the scalar subquery:
    SELECT USAGE
    FROM   (
            SELECT CV.USAGE,
                   ROW_NUMBER() OVER (PARTITION BY CV.PART_ID,
                                                   CV.PARAMETER_ID
                                      ORDER BY CV.LOG_DATE DESC) RN
            FROM COMPLEX_VIEW CV
            WHERE CV.PARAMETER_ID = 'ABC'
            AND   CV.PART_ID      = 'XYZ'
           )
    WHERE RN = 1
    
    
    Elapsed: 00:00:00.02
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
            738  consistent gets
              0  physical reads
              0  redo size
            532  bytes sent via SQL*Net to client
            524  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              1  sorts (memory)
              0  sorts (disk)
              1  rows processed
    Only 0.02 second and 738 consistent gets to select the USAGE value from the complex view! It looks like the plan is coming together. I proceeded to replace the correlated subquery with the scalar subquery so the main query becomes:
    SELECT  T1.COLUMN_1,
            T1.COLUMN_2,
            V1.COLUMN_1,
            V1.COLUMN_2,
            T2.COLUMN_1,
            T2.COLUMN_2,
            V2.COLUMN_1,
            V2.COLUMN_2,
    (
             SELECT USAGE
             FROM   (
                     SELECT CV.USAGE,
                            ROW_NUMBER() OVER (PARTITION BY CV.PART_ID,
                                                            CV.PARAMETER_ID
                                               ORDER BY CV.LOG_DATE DESC) RN
                     FROM COMPLEX_VIEW CV
                     WHERE CV.PARAMETER_ID = T3.ID
                     AND   CV.PART_ID      = T4.ID
                    )
             WHERE RN = 1
            ) USAGE,
            .
            .
            .
            24 additional columns 
            .
            .
            .       
    FROM  TABLE_1 T1,
          TABLE_2 T2,
          TABLE_3 T3,
          TABLE_4 T4,
          VIEW_1  V1,
          VIEW_2  V2,
          .
          .
          An additional mix of 7 tables and views
          .
          .
    WHERE T1.COLUMN_4 = T2.COLUMN_5
    AND   T2.COLUMN_7 = T3.COLUMN_8
    .
    .
    .
    AND   T5.ID = 'ABC123'
    Notice the complex view is not part of the FROM section and there are no joins to the complex view in the WHERE clause. I executed the new and improved query and got the following error:
    ERROR at line 17:
    ORA-00904: "T4"."ID": invalid identifier
    The excitement was extinguished for a brief moment while I realized my mistake. How come T4.ID is an invalid identifier when I know ID is a valid column on TABLE_4? The problem is that TABLE_4 is not visible inside the inline view of the scalar subquery. The complex view is two levels deep so I can’t join CV and T4. How can I hide the logic of the scalar subquery in a way that allows me to join the complex view and TABLE_4? A view that implements the core logic of the scalar subquery achieves the desired result so I created the following view:
    CREATE OR REPLACE VIEW CURRENT_USAGE
    AS
      SELECT USAGE,
             PART_ID,
             PARAMETER_ID
      FROM
        (
         SELECT CV.USAGE,
                CV.PART_ID,
                CV.PARAMETER_ID,
                ROW_NUMBER() OVER (PARTITION BY CV.PART_ID,
                                                CV.PARAMETER_ID
                                   ORDER BY CV.LOG_DATE DESC) RN
         FROM COMPLEX_VIEW CV
        )
      WHERE RN = 1;
    The main query needs to be modified again to reference the newly created view CURRENT_USAGE so it becomes:
    SELECT  T1.COLUMN_1,
            T1.COLUMN_2,
            V1.COLUMN_1,
            V1.COLUMN_2,
            T2.COLUMN_1,
            T2.COLUMN_2,
            V2.COLUMN_1,
            V2.COLUMN_2,
    (
             SELECT USAGE
             FROM   CURRENT_USAGE CU
             WHERE  CU.PARAMETER_ID = T3.ID
             AND    CU.PART_ID      = T4.ID
            )
            USAGE,
            .
            .
            .
            24 additional columns 
            .
            .
            .       
    FROM  TABLE_1 T1,
          TABLE_2 T2,
          TABLE_3 T3,
          TABLE_4 T4,
          VIEW_1  V1,
          VIEW_2  V2,
          .
          .
          An additional mix of 7 tables and views
          .
          .
    WHERE T1.COLUMN_4 = T2.COLUMN_5
    AND   T2.COLUMN_7 = T3.COLUMN_8
    .
    .
    .
    AND   T5.ID = 'ABC123'
    This time around the only surprise was the following runtime statistics:
    Statistics
    ----------------------------------------------------------
              2  recursive calls
              0  db block gets
          28316  consistent gets
              0  physical reads
              0  redo size
           3328  bytes sent via SQL*Net to client
            524  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              4  sorts (memory)
              0  sorts (disk)
              1  rows processed
    The new query returned the same data as the original query while performing a fraction of the work. Although 28,316 consistent gets is a bit high to return one row, this value is quite handsome when compared to the original value of 65 million consistent gets. This translates into a 99.96% improvement. Regarding response time, the original query took 13 minutes to complete while the new query only requires 0.3 second to generate results, also a 99.96% improvement.

    Combining the right mix of database objects and SQL features helped me achieve such dramatic improvement. I hope my experience will help you consider creative solutions when faced with challenging SQL performance issues.
  6. ORA-00130: invalid listener address...

    The actual error was:

    SQL>STARTUP;
    
    ORA-00119: invalid specification for system parameter LOCAL_LISTENER
    ORA-00130: invalid listener address '(ADDRESS=(PROTOCOL=TCP)(HOST=oracle)(PORT=1521))
    I had finally managed to create my 11gR2 instance when I got this. So what happened?

    1. Started OEL 5.5 64 bit VM
    2. Logged in as user oracle
    3. Opened terminal and ran . oraenv
    4. sqlplus / as sysdba
    5. Issued the startup command.

    ORA-00130 from the docs:
    Cause: The listener address specification is not valid.
    Action: Make sure that all fields in the listener address (protocol, port, host, key, ...) are correct.

    So it has something to do with how I configured everything. What else did I change on the system?

    After installing the database, I ran netca to set up the listener. I manually edited the file to change localhost.localdomain to just localhost. I also added an entry in the tnsnames.ora file to point to the listener.

    From a system perspective, I decided I didn't like "new-host" showing up on my router configuration page. So I changed the hostname to oracle. I used the network GUI tool, not the CLI (still hazy on how exactly that is done).

    I'm back to my sql prompt.
    SQL>STARTUP;
    
    ORA-00119: invalid specification for system parameter LOCAL_LISTENER
    ORA-00130: invalid listener address '(ADDRESS=(PROTOCOL=TCP)(HOST=oracle)(PORT=1521))
    Come on!

    I then asked The Google Machine for help. That led me to this thread on OTN. About 6 or 7 replies in, Hans Forbrich offers up some very helpful troubleshooting tips.

    1. Check that your environment variables are set. Check.
    2. Make sure the listener is started. Check.

    There was a caveat for #2 though. If your listener blew up on start, check these other things. That's when I saw cat /etc/hosts and his output for that. I quickly checked mine and saw this:
    [oracle@oracle bin]$ cat /etc/hosts
    # Do not remove the following line, or various programs
    # that require network functionality will fail.
    127.0.0.1               localhost.localdomain localhost
    ::1             localhost6.localdomain6 localhost6
    Ah...where's oracle? I tried pinging oracle, no response. I open up the file and add it in:
    [oracle@oracle bin]$ cat /etc/hosts
    # Do not remove the following line, or various programs
    # that require network functionality will fail.
    127.0.0.1               localhost.localdomain localhost oracle
    ::1             localhost6.localdomain6 localhost6
    I ping oracle again, response!

    Start and restart the listener. tnsping TESTING OK!
    SQL> startup;
    ORACLE instance started.
    
    Total System Global Area 1068937216 bytes
    Fixed Size                  2220200 bytes
    Variable Size             616566616 bytes
    Database Buffers          444596224 bytes
    Redo Buffers                5554176 bytes
    Database mounted.
    Database opened.
    SQL> 
    Awesome.

    In my defense (or will this be my excuse?), I don't do this everyday, or ever week, or every month. It is a once a quarter, at best, exercise. I forget things. Next time, I won't forget. If I do, I'll have this helpful page to remind me what an ID10T I am.
  7. Fun with Service Accounts

    Using a service account to access a production database, my login script returns the following:

    SQL*Plus: Release 11.2.0.1.0 Production on Sat Oct 2 08:02:11 2010
    
    Copyright (c) 1982, 2010, Oracle.  All rights reserved.
    
    
    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options
    
    
    ***roles granted***
    
    ROLE
    -------------------------------
    CONNECT
    RESOURCE
    DBA
    SELECT_CATALOG_ROLE
    EXECUTE_CATALOG_ROLE
    DELETE_CATALOG_ROLE
    EXP_FULL_DATABASE
    IMP_FULL_DATABASE
    OLAP_DBA
    XDBADMIN
    DATAPUMP_EXP_FULL_DATABASE
    DATAPUMP_IMP_FULL_DATABASE
    XDB_SET_INVOKER
    OLAP_XS_ADMIN
    JAVA_ADMIN
    HS_ADMIN_ROLE
    JAVA_DEPLOY
    GATHER_SYSTEM_STATISTICS
    SCHEDULER_ADMIN
    CERIDIAN_ROLE
    
    20 rows selected.
    
    
    ***system privileges granted***
    
    PRIVILEGE
    -------------------------------
    ADMINISTER ANY SQL TUNING SET
    ADMINISTER DATABASE TRIGGER
    ADMINISTER RESOURCE MANAGER
    ADMINISTER SQL MANAGEMENT OBJECT
    ADMINISTER SQL TUNING SET
    ADVISOR
    ALTER ANY ASSEMBLY
    ALTER ANY CLUSTER
    ALTER ANY CUBE
    ALTER ANY CUBE DIMENSION
    ALTER ANY DIMENSION
    ALTER ANY EDITION
    ALTER ANY EVALUATION CONTEXT
    ALTER ANY INDEX
    ALTER ANY INDEXTYPE
    ALTER ANY LIBRARY
    ALTER ANY MATERIALIZED VIEW
    ALTER ANY MINING MODEL
    ALTER ANY OPERATOR
    ALTER ANY OUTLINE
    ALTER ANY PROCEDURE
    ALTER ANY ROLE
    ALTER ANY RULE
    ALTER ANY RULE SET
    ALTER ANY SEQUENCE
    ALTER ANY SQL PROFILE
    ALTER ANY TABLE
    ALTER ANY TRIGGER
    ALTER ANY TYPE
    ALTER DATABASE
    ALTER PROFILE
    ALTER RESOURCE COST
    ALTER ROLLBACK SEGMENT
    ALTER SESSION
    ALTER SYSTEM
    ALTER TABLESPACE
    ALTER USER
    ANALYZE ANY
    ANALYZE ANY DICTIONARY
    AUDIT ANY
    AUDIT SYSTEM
    BACKUP ANY TABLE
    BECOME USER
    CHANGE NOTIFICATION
    COMMENT ANY MINING MODEL
    COMMENT ANY TABLE
    CREATE ANY ASSEMBLY
    CREATE ANY CLUSTER
    CREATE ANY CONTEXT
    CREATE ANY CUBE
    CREATE ANY CUBE BUILD PROCESS
    CREATE ANY CUBE DIMENSION
    CREATE ANY DIMENSION
    CREATE ANY DIRECTORY
    CREATE ANY EDITION
    CREATE ANY EVALUATION CONTEXT
    CREATE ANY INDEX
    CREATE ANY INDEXTYPE
    CREATE ANY JOB
    CREATE ANY LIBRARY
    CREATE ANY MATERIALIZED VIEW
    CREATE ANY MEASURE FOLDER
    CREATE ANY MINING MODEL
    CREATE ANY OPERATOR
    CREATE ANY OUTLINE
    CREATE ANY PROCEDURE
    CREATE ANY RULE
    CREATE ANY RULE SET
    CREATE ANY SEQUENCE
    CREATE ANY SQL PROFILE
    CREATE ANY SYNONYM
    CREATE ANY TABLE
    CREATE ANY TRIGGER
    CREATE ANY TYPE
    CREATE ANY VIEW
    CREATE ASSEMBLY
    CREATE CLUSTER
    
    PRIVILEGE
    -------------------------------
    CREATE CUBE
    CREATE CUBE BUILD PROCESS
    CREATE CUBE DIMENSION
    CREATE DATABASE LINK
    CREATE DIMENSION
    CREATE EVALUATION CONTEXT
    CREATE EXTERNAL JOB
    CREATE INDEXTYPE
    CREATE JOB
    CREATE LIBRARY
    CREATE MATERIALIZED VIEW
    CREATE MEASURE FOLDER
    CREATE MINING MODEL
    CREATE OPERATOR
    CREATE PROCEDURE
    CREATE PROFILE
    CREATE PUBLIC DATABASE LINK
    CREATE PUBLIC SYNONYM
    CREATE ROLE
    CREATE ROLLBACK SEGMENT
    CREATE RULE
    CREATE RULE SET
    CREATE SEQUENCE
    CREATE SESSION
    CREATE SYNONYM
    CREATE TABLE
    CREATE TABLESPACE
    CREATE TRIGGER
    CREATE TYPE
    CREATE USER
    CREATE VIEW
    DEBUG ANY PROCEDURE
    DEBUG CONNECT SESSION
    DELETE ANY CUBE DIMENSION
    DELETE ANY MEASURE FOLDER
    DELETE ANY TABLE
    DEQUEUE ANY QUEUE
    DROP ANY ASSEMBLY
    DROP ANY CLUSTER
    DROP ANY CONTEXT
    DROP ANY CUBE
    DROP ANY CUBE BUILD PROCESS
    DROP ANY CUBE DIMENSION
    DROP ANY DIMENSION
    DROP ANY DIRECTORY
    DROP ANY EDITION
    DROP ANY EVALUATION CONTEXT
    DROP ANY INDEX
    DROP ANY INDEXTYPE
    DROP ANY LIBRARY
    DROP ANY MATERIALIZED VIEW
    DROP ANY MEASURE FOLDER
    DROP ANY MINING MODEL
    DROP ANY OPERATOR
    DROP ANY OUTLINE
    DROP ANY PROCEDURE
    DROP ANY ROLE
    DROP ANY RULE
    DROP ANY RULE SET
    DROP ANY SEQUENCE
    DROP ANY SQL PROFILE
    DROP ANY SYNONYM
    DROP ANY TABLE
    DROP ANY TRIGGER
    DROP ANY TYPE
    DROP ANY VIEW
    DROP PROFILE
    DROP PUBLIC DATABASE LINK
    DROP PUBLIC SYNONYM
    DROP ROLLBACK SEGMENT
    DROP TABLESPACE
    DROP USER
    ENQUEUE ANY QUEUE
    EXECUTE ANY ASSEMBLY
    EXECUTE ANY CLASS
    EXECUTE ANY EVALUATION CONTEXT
    EXECUTE ANY INDEXTYPE
    
    PRIVILEGE
    -------------------------------
    EXECUTE ANY LIBRARY
    EXECUTE ANY OPERATOR
    EXECUTE ANY PROCEDURE
    EXECUTE ANY PROGRAM
    EXECUTE ANY RULE
    EXECUTE ANY RULE SET
    EXECUTE ANY TYPE
    EXECUTE ASSEMBLY
    EXPORT FULL DATABASE
    FLASHBACK ANY TABLE
    FLASHBACK ARCHIVE ADMINISTER
    FORCE ANY TRANSACTION
    FORCE TRANSACTION
    GLOBAL QUERY REWRITE
    GRANT ANY OBJECT PRIVILEGE
    GRANT ANY PRIVILEGE
    GRANT ANY ROLE
    IMPORT FULL DATABASE
    INSERT ANY CUBE DIMENSION
    INSERT ANY MEASURE FOLDER
    INSERT ANY TABLE
    LOCK ANY TABLE
    MANAGE ANY FILE GROUP
    MANAGE ANY QUEUE
    MANAGE FILE GROUP
    MANAGE SCHEDULER
    MANAGE TABLESPACE
    MERGE ANY VIEW
    ON COMMIT REFRESH
    QUERY REWRITE
    READ ANY FILE GROUP
    RESTRICTED SESSION
    RESUMABLE
    SELECT ANY CUBE
    SELECT ANY CUBE DIMENSION
    SELECT ANY DICTIONARY
    SELECT ANY MINING MODEL
    SELECT ANY SEQUENCE
    SELECT ANY TABLE
    SELECT ANY TRANSACTION
    UNDER ANY TABLE
    UNDER ANY TYPE
    UNDER ANY VIEW
    UNLIMITED TABLESPACE
    UPDATE ANY CUBE
    UPDATE ANY CUBE BUILD PROCESS
    UPDATE ANY CUBE DIMENSION
    UPDATE ANY TABLE
    
    202 rows selected.
    Awesome!
  8. 1Z0-052 - Administering User Security

    Main

    Create and manage database user accounts

    CREATE USER

    Grant and revoke privileges

    GRANT SELECT ON table_01 TO jkuramot;

    REVOKE SELECT ON table_01 FROM jkuramot;

    Create and manage roles

    CREATE ROLE

    Create and manage profiles

    A profile is a named set of resource limits and password parameters that restrict database usage and instance resources for a user. You can assign a profile to each user, and a default profile to all others. Each user can have only one profile, and creating a new one supersedes and earlier version.

    Profiles are used to manage the resource limits of related users.

    Profile resource limits are enforced only when you enable resource limitation for the associated database. Enabling this limitation can occur either before starting up the database (using the RESOURCE_LIMIT initialization parameter) or while it is open (using the ALTER SYSTEM statement).

    Though password parameters reside in profiles, they are unaffected by RESOURCE_LIMIT or ALTER SYSTEM and password management is always enabled.


    CREATE PROFILE

    Main
  9. APEX: Database Links

    I've talked about APEX being hardly known among quite a few people in the Oracle world...at least the ones I have worked with. When I first moved to Tampa, people had heard of it, but never got around to trying it out. This was late 2006, around version 2.2. My next job, same thing. The DBA had heard of it, but hadn't used it yet. Thankfully he was open and willing to try out new things. This is the same guy who had an 11gR1 RAC install within months of 11g being released in 2007. Can you say glutton for punishment?

    My next assignment had it installed, but it was mostly for reporting so it had it's own instance. APEX utilized database links to access other databases. I was tasked with re-engineering their payment processing application using APEX as a skin. I worked to convince them that APEX needed to be installed on the same machine. The DBA fought me tooth and nail (and ultimately won) on that issue. I didn't get the opportunity to finish that application.

    Anyway, the point I try to make is that you take away a lot of the features of APEX when you use it across a database link.

    I'm not one to use a lot of the wizards or declarative stuff, I like to use packages and use the "Create Procedure from Form" wizard.

    It's amazingly simple and only requires a little tweaking on the front end to finish up a input/update/delete form.

    Using database links though, this isn't possible.

    For example:

    CREATE USER table_owner
      IDENTIFIED BY testing
      DEFAULT TABLESPACE users
      QUOTA 10M ON users;
    
    CREATE DATABASE LINK my_application
      CONNECT TO table_owner 
      IDENTIFIED BY testing
      USING 'TESTING';
    That's a loopback database link pointing to my sandbox.
    CREATE TABLE table_owner.t
    (
      id NUMBER(10)
        CONSTRAINT pk_id PRIMARY KEY,
      first_name VARCHAR2(30)
        CONSTRAINT nn_firstname_t NOT NULL,
      last_name VARCHAR2(30)
        CONSTRAINT nn_lastname_t NOT NULL
    );
    
    CREATE SEQUENCE table_owner.sq_t
      START WITH 100
      INCREMENT BY 1
      CACHE 10
      NOCYCLE;
    
    CREATE OR REPLACE
    FUNCTION table_owner.create_t
      ( p_first_name IN VARCHAR2,
        p_last_name IN VARCHAR2 ) RETURN NUMBER
    IS
      l_id NUMBER;
    BEGIN
      INSERT INTO t
        ( id,
          first_name,
          last_name )
      VALUES
        ( sq_t.nextval,
          p_first_name,
          p_last_name )
      RETURNING id INTO l_id;
    
      RETURN l_id;
    END create_t;
    /
    show errors
    I then create some basic objects in the TABLE_OWNER schema including a function that returns the ID of the newly created record. On to APEX where I have created a simple one page app. This workspace is mapped to my schema, CJUSTICE and the database link is private to that schema.

    Now I want to create a new region on the page

    create new region

    Click Next.

    create form

    Click Next.

    create form from procedure

    Click Next.

    Now select your schema. Your workspace can map to multiple schemas, but I have only one, my own.

    select schema

    Click Next.

    Now click on the little button thing in red

    red button thingy

    You'll see a popup window listing out all the procedure and functions in your schema.

    list of objects

    So it's not there...but it is in another schema (and since the database link is using the schema owner, there is no need to GRANT EXECUTE on the procedure).



    Nothing there.

    Let's try entering it in manually

    error

    Well that sucks.

    Can I do it manually?

    First I create the process:



    Build a simple form:

    simple form

    Enter in some data, click on submit.

    JP form

    Then verify:
    TABLE_OWNER@TESTING>SELECT * FROM T;
    
            ID FIRST_NAME                     LAST_NAME
    ---------- ------------------------------ ------------------------------
           100 JOHN                           PIWOWAR
    Amusingly, I seemed to recall an issue, a few years back about using the RETURNING clause across a database link. I wonder if that's because it's not a true database link? (Figured it out the next day of course, ORA-22816)

    Anyway, the point is, install APEX on the database you plan on building your application. You'll only add unnecessary work and time to your development efforts which means you might as well use Java. :)
  10. 1Z0-052 - Configuring the Oracle Network Environment

    Main

    Configure and Manage the Oracle Network

    There haven't been too many times when I have used the tools provided by Oracle to manage net services. Mostly, I take an existing file and change it to suit my current needs. The biggest reason for this is probably because I never quite understood what exactly was being asked for.

    The 3 files typically involved are sqlnet.ora, listener.ora and tnsnames.ora which can be found in the <ORACLE_HOME>/network/admin folder.

    Typically, these files are created by Oracle on installation. Perusing the files that are on my 11.2 installation, they appear to be the default (and I don't believe I have ever had need to modify them).

    Here's the default entry for sqlnet.ora
    # sqlnet.ora Network Configuration File: 
    # /u01/app/oracle/product/11.2.0/dbhome_1/network/admin/sqlnet.ora
    # Generated by Oracle configuration tools.
    
    NAMES.DIRECTORY_PATH= (TNSNAMES, EZCONNECT)
    
    ADR_BASE = /u01/app/oracle
    I've seen NAMES.DIRECTORY_PATH before, but it appears that ADR_BASE is new to 11g. I'll have to read up a bit on that one and get back to you. To read up on the different parameters for the sqlnet.ora file, go here.

    As far as the tnsnames.ora goes, I don't believe it is required to be configured on the database server itself. This is mainly a client configuration file. Here is what it looks like on my server:
    TESTING =
      (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCP)(HOST = oracledb)(PORT = 1521))
        (CONNECT_DATA =
          (SERVER = DEDICATED)
          (SERVICE_NAME = testing)
        )
      )
    And here is the entry on my host machine:
    TESTING =
      ( DESCRIPTION = 
        ( ADDRESS = ( PROTOCOL = TCP )( HOST = 192.168.1.5 )( PORT = 1521 ) )
        ( CONNECT_DATA =
          ( SERVER = DEDICATED )
          ( SERVICE_NAME = testing )
        )
      )
    Note the one difference between the two, the HOST. The HOST tells you (or your client tool really) on which server this database resides. If this were a RAC instance, you would see multiple ADDRESS sections. That is beyond the scope of this test however.

    To read more about the parameters for a tnsnames.ora file, go here.

    Finally you have your listener.ora file. This file is absolutely necessary on your database server. The Oracle Net Listener is a separate process that runs on the database server. It receives incoming client connection requests and manages the traffic of these requests to the database server.

    Here's what the default listener.ora file looks like on my installation:
    LISTENER =
      (DESCRIPTION_LIST =
        (DESCRIPTION =
          (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
          (ADDRESS = (PROTOCOL = TCP)(HOST = oracledb)(PORT = 1521))
        )
      )
    
    ADR_BASE_LISTENER = /u01/app/oracle
    Again, the ADR_BASE_LISTENER is new to 11g and requires further research.

    Using the Oracle Shared Server architecture



    Documentation

    In a shared server configuration, client user processes connect to a dispatcher. The dispatcher can support multiple client connections concurrently. Each client connection is bound to a virtual circuit, which is a piece of shared memory used by the dispatcher for client database connection requests and replies. The dispatcher places a virtual circuit on a common queue when a request arrives.

    An idle shared server process picks up the virtual circuit from the common queue, services the request, and relinquishes the virtual circuit before attempting to retrieve another virtual circuit from the common queue. This approach enables a small pool of server processes to serve a large number of clients. A significant advantage of shared server architecture over the dedicated server model is the reduction of system resources, enabling the support of an increased number of users.

    For even better resource management, shared server can be configured for connection pooling. Connection pooling lets a dispatcher support more users by enabling the database server to time-out protocal connections and to use those connections to service an active session. Further, shared server can be configured for session multiplexing, which combines multiple sessions for transmission over a single network connection in order to conserve the operating system's resources.

    Shared server architecture requires Oracle Net Services. User processes targeting the shared server must connect through Oracle Net Services, even if they are on the same machine as the Oracle Database instance.

    Main
  1. 1
  2. Next ›
  3. Last »