Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Khan.

Asked: March 29, 2003 - 10:46 am UTC

Last updated: October 25, 2007 - 6:35 pm UTC

Version: 9.2.0.2

Viewed 10K+ times! This question is

You Asked

Hi Tom,

Can you give us some examples of the benefits of using NOT NULL constraints on columns? Thanks.

Kashif

and Tom said...

funny -- wonder why there always must be "benefits". It seems obvious that if you have a business rule that says "this column MUST not be null", a not null constraint would be called for..

Well, benefits --

o it adds semantic meaning to your data model. You KNOW that the column will always contain a value.

o it removes ambiguity. "find me all of the people who are not clerks". Seems obvious:

select * from emp where job <> 'CLERK';

well, thats wrong

select * from emp where job <> 'CLERK' or job is NULL;

is correct. Many query tools will either
a) get it wrong (wrong answer, that is a negative)
b) get it right -- but therefore get it slower in many cases.

o it allows for access paths that did not otherwise exist. Consider this simple 10,000 row example:

ops$tkyte@ORA920> create table t1 as select * from all_objects where rownum <= 10000;

Table created.

ops$tkyte@ORA920> create table t2 as select * from all_objects where rownum <= 9950;

Table created.

ops$tkyte@ORA920> create index t2_idx on t2(object_id);

Index created.

ops$tkyte@ORA920>
ops$tkyte@ORA920> alter table t2 modify object_id null;

Table altered.

ops$tkyte@ORA920>
ops$tkyte@ORA920> analyze table t1 compute statistics
2 for table
3 for all indexes
4 for all indexed columns;

Table analyzed.

ops$tkyte@ORA920>
ops$tkyte@ORA920> analyze table t2 compute statistics
2 for table
3 for all indexes
4 for all indexed columns;

Table analyzed.

ops$tkyte@ORA920>
ops$tkyte@ORA920> alter session set sql_trace=true;

Session altered.

ops$tkyte@ORA920>
ops$tkyte@ORA920> select count(*)
2 from t1 nullable
3 where object_id not in ( select object_id from t2 );

COUNT(*)
----------
50

ops$tkyte@ORA920>
ops$tkyte@ORA920> alter table t2 modify object_id not null;

Table altered.

ops$tkyte@ORA920>
ops$tkyte@ORA920> select count(*)
2 from t1 notnull
3 where object_id not in ( select object_id from t2 );

COUNT(*)
----------
50



tkprof says:


select count(*)
from t1 nullable
where object_id not in ( select object_id from t2 )

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.09 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 16.67 17.68 0 735876 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 16.68 17.78 0 735876 0 1

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
50 FILTER
10000 TABLE ACCESS FULL T1
9950 TABLE ACCESS FULL T2
--------------------------------------------------------------------------------
select count(*)
from t1 notnull
where object_id not in ( select object_id from t2 )

call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.01 0.03 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.02 0.06 0 161 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.04 0.09 0 161 0 1

Rows Row Source Operation
------- ---------------------------------------------------
1 SORT AGGREGATE
50 HASH JOIN ANTI
10000 TABLE ACCESS FULL OBJ#(45593)
9950 INDEX FULL SCAN OBJ#(45595) (object id 45595)


ahh, the difference a constraint makes!


In short -- the more information you give the database, the better the quality of the plans. Not null impacts the optimizer, query rewrite, even the queries you must type in to get the correct answer.

Every column that is NOT NULLABLE -- should be marked as such.

Rating

  (14 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Making 'NOT NULL' as the default

Logan Palanisamy, March 31, 2003 - 7:48 pm UTC

Tom,

You have demonstrated very well the usefulness of the NOT NULL constraint. Despite all its benefits, the default is still NULL when we create a table. Wouldn't it be nice if the default is NOT NULL. One should intentionally set it to NULL if there is a real need.

May be, Oracle should come up with a new init.ora which sets the database default NULL/NOT NULL behavior for all newly created columns. The default value of this new init.ora parameter can be set to NULL to simulate the current behavior. Once you set this parameter to NOT NULL, all new columns created hence forth will be NOT NULL by default which one can override with NULL where it is needed.

Do you think of any drawbacks to this approach.

Tom Kyte
March 31, 2003 - 8:31 pm UTC

well, it would be nice but a disaster.

far far far too much legacy code relies on the other way. almost NOTHING would work - even with that switch. virtually every application written would "break"

Dave, April 01, 2003 - 1:08 am UTC

Perhaps another disadvantage of automatically constraining new columns to not null would be that it would encourage the idle among us towards not naming their constraints. If there's one thing i hate, it's a system-named constraint.

create table my_table
(
my_column1 number constraint nn1my_table not null,
my_column2 number constraint nn2my_table not null,
my_column3 number constraint nn2my_table not null
)

vs

create table my_table
(
my_column1 number not null,
my_column2 number not null,
my_column3 number not null
)

It's not much to ask, people.

Michael, April 01, 2003 - 3:13 pm UTC

What is the big advantage for naming NN constraint versus not?

Tom Kyte
April 01, 2003 - 7:30 pm UTC

clarity,
meaning,
documentation,
readability in the data dictionary,
more meaningful information from error messages...


Not only that -- but I've seen massive issues with unnamed constraints with export import.

Here is the scenario:

o you export from db1
o you import into db2
o once a week you truncate and import into db2 

over time, you notice that db2 is dog slow -- whats up?  well, someone had a nasty un-named constraint in that and now you have it 500 times.


ops$tkyte@ORA920> create table t ( x int check ( x > 0 ) );

Table created.

ops$tkyte@ORA920> select count(*) from user_constraints where table_name = 'T';

  COUNT(*)
----------
         1

ops$tkyte@ORA920> !exp userid=/ tables=t

Export: Release 9.2.0.3.0 - Production on Tue Apr 1 19:32:23 2003

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to: Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production
Export done in WE8ISO8859P1 character set and AL16UTF16 NCHAR character set

About to export specified tables via Conventional Path ...
. . exporting table                              T          0 rows exported
Export terminated successfully without warnings.

ops$tkyte@ORA920> !imp userid=/ full=y ignore=y

Import: Release 9.2.0.3.0 - Production on Tue Apr 1 19:32:32 2003

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to: Oracle9i Enterprise Edition Release 9.2.0.3.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production

Export file created by EXPORT:V09.02.00 via conventional path
import done in WE8ISO8859P1 character set and AL16UTF16 NCHAR character set
. importing OPS$TKYTE's objects into OPS$TKYTE
. . importing table                            "T"          0 rows imported
Import terminated successfully without warnings.

ops$tkyte@ORA920> select count(*) from user_constraints where table_name = 'T';

  COUNT(*)
----------
         2

ops$tkyte@ORA920>


Every time I import -- i get that constraint over and over (we cannot tell they are the same - -they have no name).  system gets REALLY slow.....


Name things.  You won't be sorry you did -- only sorry if you don't 

Excellent point!!!

A reader, April 01, 2003 - 8:01 pm UTC


How to get out of unnamed constraints trap?

Arun Gupta, April 02, 2003 - 10:48 pm UTC

Tom
I recently fell into the trap of unnamed constraints, lack of naming standards and my own laziness to try and develop some. The situation is that some columns have both a NOT NULL constraint and a check constraint which allows only 'Y' and 'N'. Now I wanted to drop only the check constraint only from columns. How do I filter them out ? The column containing constraint text is a LONG and cannot be used in where clause.

Thanks


Tom Kyte
April 03, 2003 - 7:41 am UTC

search this site for longsubstr and read all of the hits.

Not nulls.

Kashif, April 03, 2003 - 4:05 pm UTC

Thanks Tom, I believe the word I had left out was 'performance' from the question. I was looking for the performance benefits of using NOT NULL constraints. Though I have tested a few things after your response and some of the responses from queries using NOT NULL columns with indexes on them has gone up, after I made changes to make them NOT NULL. Also got to use some fast full scans as a result. Thanks as always.

Kashif

NOT NULL performance

Duke Ganote, June 14, 2004 - 10:40 am UTC

I assume Kashif's performance improvement is due to the specific queries run, and B*tree indexes not storing NULL values (as you discuss in your book "Expert 1-on-1 Oracle" in the section titled "Indexes and Nulls").

Certainly, NOT NULLilfying a column requires some pseudo-NULL value (if there are truly NULLs). But introducing a pseudo-NULL brings issues of its own (such as having a difference pseudo-NULL for each datatype and potentially each column). A function-based index, as touched on in the question titled "Finding NULLs by index" at </code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:434019666272, <code>
appears to be one such approach.

naming not null constraints in an alter table command

Susan, June 23, 2004 - 11:11 am UTC

Tom,

I need to alter a table by adding a not null constraint. I'd like to avoid the system generated name, but, I can't seem to find the right syntax in the docs.

alter table add constraint nn_uid u_id not null; (and other attempts) throws errors. Can this be done? Thanks.

Tom Kyte
June 23, 2004 - 11:41 am UTC



alter table t modify y constraint y_not_null not null;


Quick question.

Kashif, February 17, 2005 - 1:07 pm UTC

Hi Tom,

I've been trying to execute an import from a user-level export dump file into an empty schema, and for some reason the import is not creating not null constraints on tables, specifically the ones NOT associated with a primary key constraint. Of the top of your head, do you know if this is a known bug or something, or maybe a combination of parameters I'm not doing right? I'll post a complete example if I am not able to resolve this, but I thought I'd ask you to see if you knew something of the top of your head. Both the export and the import are done on version 9.2.0.5. Thanks and I'll post if I figure it out.

Kashif

Tom Kyte
February 17, 2005 - 2:07 pm UTC

not that I am aware of, do an imp userid=u/p full=y indexfile=foo.sql and see if they are there.

Thanks.

Kashif, February 17, 2005 - 6:06 pm UTC

Hi Tom,

Sorry for the false alarm, I was getting confused and didn't stop to think that I had pre-created those tables before doing the import, and that particular DDL script did not have the NOT NULL constraints on those columns... Silly me ;) Thanks and sorry for bothering you.

Kashif

(re)naming NOT NULL constraints -- thanks!

Duke Ganote, October 25, 2007 - 1:13 pm UTC

Thanks for this (second above)
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:8906942258938#20120536919337

I'd wondered about how to accomplish that, and yet it is in the documentation:

http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14251/adfns_constraints.htm#sthref622

A NOT NULL constraint is specified like this:

ALTER TABLE emp MODIFY ename NOT NULL;

Tom Kyte
October 25, 2007 - 6:35 pm UTC

yes, that is one way to do it - a simple example is just that in the documentation. A simple example.

NOT NULL does give better quality plans

catmando, October 26, 2007 - 1:26 am UTC

As Tom, said, more information, better plans. This year I have seen big performance gains in a warehouse setting when dealing with NOT IN constructs with the appropriate NOT NULL constraints. I had a few queries that went from 1+ hours or never finishing to 1 second results. That's not true of all situations/queries, but repeatable on my side.

I believe it also opens up the FAST FULL index scan across NORMAL indexes. Check the manuals on that one.

I've never seen a performance penalty of significance for putting the constraint on.

Naming (or not) NOT NULL Constraints

Duke Ganote, October 26, 2007 - 11:28 am UTC

Apologies, I misstated. It's trivial to see how to impose a NOT NULL constraint. Non-trivial to go thru the ALTER TABLE syntax options
http://tinyurl.com/27n8na
in order to figure out (or even verify) how to assign an explict name:
ALTER TABLE t MODIFY y CONSTRAINT y_not_null NOT NULL;

I was reading Dizwell's entry on naming constraints
http://www.dizwell.com/prod/node/1034
The value of explicitly-named primary, unique and foreign key constraints seemed generally accepted.

(Similar to:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:5108567080634
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:22838206832332
)
However, some argue that system-generated NOT NULL constraint name are OK; no need to explicitly name such constraints.

named not null constraint

Subrata Chattopadhya, March 19, 2010 - 1:41 pm UTC

Thanks for the named not null constraint syntex. I had a hard time finding it anywhere including Oracle manual.

More to Explore

Performance

Get all the information about database performance in the Database Performance guide.