Opening GUI Windows from the Terminal

Obviously the terminal window is command line only, so if you need to run a GUI application (typically for new installations and creating databases, but you might use the GUI tools for ASM and/or listener adminstration also) you’ll need to run the application on the server with the display showing on your local machine.  There are several steps to this, and you likely won’t need to do them all, but you might if you run into any errors.  I typically use puTTY and Exceed, but this should be similar with F-Secure/SecureCRT and Xming or whatever you’re using.

1. Enable X11 forwarding     When you first open the puTTY window, look in the left navigation pane under Connection->SSH->X11 and check the box to ‘Enable X11 forwarding’.  Then continue to login to the server as you usually do.

2. Set xhost     Run ”  xhost +  ” from your terminal window.  This will give you access to communicate to your local machine, I’m not a UNIX expert so I’m not sure of the exact mechanism that makes this work:

[charlotte@testbox ~]$ xhost +
access control disabled, clients can connect from any host

3. Find out your local IP address    On your local machine, open the command prompt and run  ”  ipconfig  ” then find your IP address, I’ve edited down this output, but find the line that says IPv4:

C:\Users\charlotte>ipconfig

IPv4 Address. . . . . . . . . . . : 123.456.789.012

4. Set the DISPLAY variable    Back in your puTTY window, set the DISPLAY variable to your IP address with 0:0 at the end:

[charlotte@testbox ~]$ export DISPLAY=123.456.789.012:0.0
[charlotte@testbox ~]$ echo $DISPLAY
123.456.789.012:0.0

5. Open your xwindows server    On your local machine open Exceed or Xming or whatever xwindows server you’re using.  (Yes, the server is your local machine and the client is the database server, long story… )  A window shouldn’t open, but you can see the application running if you check the task manager.

 

You should be able to go ahead and run your server-side GUI application now.  You can test with  ”  xclock  ”  which should open a small analog clock on your local machine.

more on index/constraint creation…

This post is to explain a little more about a topic I touched on when describing how to generate ddl, which is why creating indexes and constraints separate from your table definition is a good idea.  If you just want to achieve similar functionality in a new environment this probably isn’t a big deal, but it’s something to be aware of and will be necessary if you need an exact copy for testing or migrating.

The idea here is that in order to have full control over your table/index/constraint structure you need to create all of these objects individually.  Allowing Oracle to choose the “best” implementation may not give the desired result, particularly if you’re creating these structures prior to loading potentially large amounts of data.  Below is an example of how things can get changed around.

–Let’s start by creating a table, index, and constraint with the preferred method, which is to create them all individually:

SQL> create table people (name varchar(20), age number(2));
Table created.

SQL> create index people_idx on people (age);
Index created.

SQL> alter table people add constraint people_pk primary key (age) using index people_idx;
Table altered.

–Now go ahead and create the ddl for the table, but set it aside for now:

SQL> set pagesize 0
SQL> set long 150000

SQL> select dbms_metadata.get_ddl('TABLE','PEOPLE','CHARLOTTE') from dual;
CREATE TABLE "CHARLOTTE"."PEOPLE"
( "NAME" VARCHAR2(20),
"AGE" NUMBER(2,0),
CONSTRAINT "PEOPLE_PK" PRIMARY KEY ("AGE")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "EORDERS_BLOB" ENABLE
) 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)
TABLESPACE "CHARLOTTE_DATA"

–Verify the index and constraint relationship:

SQL> select index_name from user_indexes where table_name='PEOPLE';
PEOPLE_IDX
SQL> select index_name from user_constraints where constraint_name='PEOPLE_PK';
PEOPLE_IDX

**You can see that the people_idx index we created is the only index on the people table, and that it is being used to enforce the people_pk constraint that we created.  If we drop the constraint, the index still exists:

SQL> alter table people drop constraint people_pk;
Table altered.

SQL> select index_name from user_indexes where table_name='PEOPLE';
PEOPLE_IDX

–Now drop the table, and lets recreate it using the ddl that we generated.  Again, I don’t typically specify all of the storage information when creating objects, but for the sake of the example we’ll use the entire ddl as in theory this should give us a structural copy of the table.

SQL> drop table people;
Table dropped.

SQL> CREATE TABLE "CHARLOTTE"."PEOPLE"
2  (    "NAME" VARCHAR2(20),
3  "AGE" NUMBER(2,0),
4  CONSTRAINT "PEOPLE_PK" PRIMARY KEY ("AGE")
5  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
6  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
7  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
8  TABLESPACE "EORDERS_BLOB"  ENABLE
9  ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
10  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
11  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
12  TABLESPACE "CHARLOTTE_DATA";

Table created.

–And take a look at the index and constraint relationship on the new table:

SQL> select index_name from user_indexes where table_name='PEOPLE';
PEOPLE_PK

SQL> select index_name from user_constraints where constraint_name='PEOPLE_PK';
PEOPLE_PK

You can see that the index has the same name as the constraint here, and..

–If you drop the constraint the index gets dropped too:

SQL> alter table people drop constraint people_pk;
Table altered.

SQL> select index_name from user_indexes where table_name='PEOPLE';
no rows selected

WHY??

In order for unique and primary key constraints to be enforced, there must be an index on the constrained columns.  If an index exists, it can/will be used.  But if there is no existing index (which is the case when you create the constraint as part of the table definition) Oracle will create an underlying index as part of the constraint definition.  This index will “belong to” the constraint, have the same name as the constraint and as demonstrated above, will be dropped when the constraint is dropped.

Keep this in mind when you’re creating objects, particularly when you’re creating a large number of objects in a critical environment.  I’ve done a ton of database migrations, many of them involving data pump and structural changes so this was always something I paid a lot of attention to.

Leave a comment and let me know if you have any questions about this.

Querying DICT and the data dictionary

You probably know already that you can describe a table’s column structure with the ‘describe’ or ‘desc’ keywords:

SQL> describe dba_tables
SQL> desc dba_tables

But what if you don’t know the name of the table you want to describe?  When you’re working with user data this isn’t typically an issue, but when you’re working with the data dictionary (DBA_) and performance views (v$_) you might not always know the name of the table you want to query.  For example, I wanted to know how many paritions were in a particular table but DBA_TABLES doesn’t have that kind of information.  You can actually query DICT or DICTIONARY to find out.  DICT/DICTIONARY is like DBA_TABLES but for the data dictionary tables and performance views.  If you describe it:

SQL> desc dict
Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
TABLE_NAME                                         VARCHAR2(30)
COMMENTS                                           VARCHAR2(4000)

you can see that it stores the table name and a short description.  So when I want to find out about partitions “hm, the table name probably has partition in it…”

SQL> select table_name from dict where table_name like '%PARTITION%' order by 1;

TABLE_NAME
------------------------------
ALL_IND_PARTITIONS
ALL_IND_SUBPARTITIONS
ALL_LOB_PARTITIONS
ALL_LOB_SUBPARTITIONS
ALL_MVIEW_DETAIL_PARTITION
ALL_MVIEW_DETAIL_SUBPARTITION
ALL_SUBPARTITION_TEMPLATES
ALL_TAB_PARTITIONS
ALL_TAB_SUBPARTITIONS
DBA_IND_PARTITIONS
DBA_IND_SUBPARTITIONS

TABLE_NAME
------------------------------
DBA_LOB_PARTITIONS
DBA_LOB_SUBPARTITIONS
DBA_MVIEW_DETAIL_PARTITION
DBA_MVIEW_DETAIL_SUBPARTITION
DBA_SUBPARTITION_TEMPLATES
DBA_TAB_PARTITIONS
DBA_TAB_SUBPARTITIONS
USER_IND_PARTITIONS
USER_IND_SUBPARTITIONS
USER_LOB_PARTITIONS
USER_LOB_SUBPARTITIONS

TABLE_NAME
------------------------------
USER_MVIEW_DETAIL_PARTITION
USER_MVIEW_DETAIL_SUBPARTITION
USER_SUBPARTITION_TEMPLATES
USER_TAB_PARTITIONS
USER_TAB_SUBPARTITIONS

27 rows selected.

One of the table_name values returned is DBA_TAB_PARTITIONS.  Now I can describe that table:

SQL> desc dba_tab_partitions
Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
TABLE_OWNER                                        VARCHAR2(30)
TABLE_NAME                                         VARCHAR2(30)
COMPOSITE                                          VARCHAR2(3)
PARTITION_NAME                                     VARCHAR2(30)
SUBPARTITION_COUNT                                 NUMBER
HIGH_VALUE                                         LONG
HIGH_VALUE_LENGTH                                  NUMBER
PARTITION_POSITION                                 NUMBER
TABLESPACE_NAME                                    VARCHAR2(30)
PCT_FREE                                           NUMBER
PCT_USED                                           NUMBER
INI_TRANS                                          NUMBER
MAX_TRANS                                          NUMBER
INITIAL_EXTENT                                     NUMBER
NEXT_EXTENT                                        NUMBER
MIN_EXTENT                                         NUMBER
MAX_EXTENT                                         NUMBER
MAX_SIZE                                           NUMBER
PCT_INCREASE                                       NUMBER
FREELISTS                                          NUMBER
FREELIST_GROUPS                                    NUMBER
LOGGING                                            VARCHAR2(7)
COMPRESSION                                        VARCHAR2(8)
COMPRESS_FOR                                       VARCHAR2(18)
NUM_ROWS                                           NUMBER
BLOCKS                                             NUMBER
EMPTY_BLOCKS                                       NUMBER
AVG_SPACE                                          NUMBER
CHAIN_CNT                                          NUMBER
AVG_ROW_LEN                                        NUMBER
SAMPLE_SIZE                                        NUMBER
LAST_ANALYZED                                      DATE
BUFFER_POOL                                        VARCHAR2(7)
GLOBAL_STATS                                       VARCHAR2(3)
USER_STATS                                         VARCHAR2(3)

 

And find out the number of partitions in my table:

SQL> select count(*) from dba_tab_partitions where table_owner='CHARLOTTE' and table_name='EVENT';

COUNT(*)
----------
38

Error logging with DBMS_ERRLOG in 11g (and 10g)

**I did this in Oracle 11gR1 but it’s supposed to be available beginning with Oracle 10gR2

I came across this error logging utility while researching an issue.  This is great for “large” jobs that are failing because of a small number of rows.  You can skip them and deal with them later.  The idea here is to create a table that logs the rows that would normally cause a transaction to fail, and to finish the transaction using the rows that don’t cause any issue.  A simple example:

1. Create an error logging table for the table that you’re inserting into:

exec dbms_errlog.create_error_log ('YOUR_TABLE_NAME','ERROR_LOG_TABLE_NAME',NULL,NULL,TRUE);

2. Add ‘log errors into ERROR_LOG_TABLE_NAME reject limit unlimited’ to your sql statement:

insert into YOUR_TABLE_NAME (*some data*) log errors into ERROR_LOG_TABLE_NAME reject limit unlimited;

And voila!  This is enough to get you going with error logging!  Some things to keep in mind:

–Deal with the rows in the error logging table!  In my case I was working with an archiving job that sometimes ran into duplicate data and failed with ORA-00001: unique constraint violated, so the rows I logged into my error table were trash and I added a statement at the end  of the job to truncate the error logging table.  Your case might be similar or very different, just be sure you do something with the rows.

–Supposedly you can omit the ‘into ERROR_LOG_TABLE_NAME‘ from your sql:

insert into YOUR_TABLE_NAME (*some data*) log errors reject limit unlimited;

Since the procedure to create the table specifies the table you’re using and the error logging table names, Oracle should know which table to log the errors into.  This never worked for me and I kept getting ORA-00942: table or view does not exist even though I created the error logging table from the same schema.  Let me know if you get this to work.

–You can change the reject limit to something appropriate for your job.  If your job attempts to insert a million rows and 999,999 of them are failing you may want to investigate further…

insert into YOUR_TABLE_NAME (*some data*) log errors into ERROR_LOG_TABLE_NAME reject limit 1000;

–The NULLs that I used in the example are actually for the table owner and tablespace, and the TRUE value is to skip unsupported datatypes.  These are all optional, the only thing you have to specify is the name of the table you’re working with.  More info on syntax here.

 

Leave a comment to let me know what kind of things you used this for or any problems that you have with it.

Where are all the junior DBAs?

 

 

 

Hi DBAs!  My name is Charlotte and I’m an OCP Oracle DBA.

20141113_080203 (2)

I started my first DBA job immediately out of college and I felt so unprepared.  I found that most of the DBAs I worked with either started as developers and migrated into database administration, or they had prepared extensively in college.  I also came across very few DBAs with less than 10 years of experience.  I had only taken one database course in college and had never worked with unix  :-/   It was an intimidating position to be in!  Luckily I worked with a very helpful team and a great mentor who helped bring me up to speed.  But as a newbie I still had a lot of trouble understanding documentation and other blogs written by more experienced Oracle professionals.  I’m about three years in now and it’s still difficult to understand some of the documentation I find!  So I’m starting this blog to help other newbies who might be in the same situation I was in.  I’ll share things I’ve learned and things I’m currently working on, and hopefully I can explain things in a way that’s more understandable for less experienced DBAs.  My first job focused more on the physical database, lots of migrations, backup/restore operations, and performance tuning.  My new job focuses more on the database objects, plsql, and business logic.  I’ll try to get a good mix of topics, but let me know what you’d like to see or if you have any specific questions.  Leave a comment to let me know your current situation, what brought you here, and what kind of challenges you’re facing.

Good luck everyone!

Charlotte