Do foreign key constraints influence query transformations in Oracle? - performance

I have a situation like this:
create table a(
a_id number(38) not null,
constraint pk_a primary key (id)
);
create table b(
a_id number(38) not null
);
create index b_a_id_index on b(a_id);
Now b.a_id is in fact meant to be a foreign key referencing a.a_id, but it isn't formally declared as such. Obviously, it should be for integrity reasons. But does a foreign key constraint also improve join performance in general or in specific cases? If yes, for what types of query transformations?
Is there any relevant documentation about this topic?
I'm using Oracle 11g (11.2.0.2.0)

Yes, having foreign key constraints in place can improve query performance. There are various transforms that are open to the optimizer when appropriate foreign key constraints exist that are not generally available. For example, if you were to join A and B but only select data from B, the optimizer could eliminate A from the query plan entirely if there was a foreign key constraint in place (this sort of thing comes in very handy when you've got useful views that join in more tables than your current query strictly needs because you don't have to trade the performance costs of the extra joins against the code reuse from using an existing view). They also come in handy when you're doing things like using things like query rewrite to rewrite a query to use a materialized view in a data warehouse/ DSS type system.
Tom Kyte has a presentation Metadata Matters that talks about how various types of constraints, along with other pieces of metadata, can influence the optimizer.

As Justin already pointed out, JOIN elimination is an essential non-cost based SQL transformation, which can be applied based on the presence of meta data only. I have blogged about this more recently:
JOIN Elimination: An Essential Optimiser Feature for Advanced SQL Usage
10 Cool SQL Optimisations That do not Depend on the Cost Model
As I originally assumed, there are a lot of SQL transformations that depend on meta data, so adding foreign key constraints (and other constraints) definitely can impact performance in a positive way.

Related

Data consistency between Oracle tables

I have one big table A who has PK (C1, C2, C3) and many other columns, to make the select faster, a smaller table B was created with PK (C1, C2). So we can do a select by joining the two tables to find a row in A.
But the problem now is that it can happen that if data is corrupted in B which results in a joint select returns nothing but we still have a row in A.
Am I doing something wrong with this design and how can I ensure the data in those two tables are consistent?
Thanks a lot.
Standard way - if those tables are in a master-detail relationship - is to create a foreign key constraint which will prevent deleting master if details exist.
If you can fix it now, do it - then create the constraint.
If you can't, then create foreign key constraint using INITIALLY DEFERRED DEFERRABLE option so that current values aren't checked, but future DML will be.
Finally, to fetch data although certain rows don't exist any more, use outer join.
"Am I doing something wrong with this design"
Well it's hard to be sure without more details about your scenario but probably you just needed a non-unique index on A(C1, C2).
Although I would like to see some benchmarking which proves an index-range scan on your primary key index was not up to the job. Especially as it seems likely the join on table B is using that access path.
Performance tuning an Oracle database is a matter of understanding and juggling many variables. It's not just a case of "bung on another index". We need to understand what the database is actually doing and why the optimiser made that choice. So, please read this post on asking Oracle tuning questions which will give you some insight into how to approach query optimisation.

Referential Integrity and Translations

Description
Hi, so I am looking at a legacy database that includes multiple translation tables for existing tables.
So there is a laws table, but then there is also a translation_laws table:
Laws (law_id, inForceDate, type, etc)
Translation_Laws (law_id, lang_code, translation)
There is also a law_type table:
Law_Type (law_type_id, description, isDecreed, etc.)
Translation_Law_Type(law_type_id, lang_code, translation)
So, with the following scheme referential integrity is maintained, but you end up with multiple translations tables.
I would prefer to make one table with the following format:
translations(table_name, id, lang_code, translation)`
This would basically be like bundle, key, lang_code, label. I could also combine bundle+key+lang_code into one varchar key: bundle.key.lang_code.
However, I don't see much of a way to define a relationship in Oracle SQL.
Questions:
Any Ideas how to define a relationship while using Integer IDs??
Would it be so bad to NOT to define a relationship in the database?
Only solution I can think of would be to try add a String foreign key to every table needing a translation (aaa.bbb.ccc.ddd) that is unique.
Update
Currently I have done away with the official relationships in the DB and made the following type of schema:
CREATE TABLE TRANSLATIONS(
DESCRIPTION_ENTITY VARCHAR(30) NOT NULL,
DESCRIPTION_COLUMN VARCHAR(30) NOT NULL,
KEY_OR_ID VARCHAR(30) NOT NULL,
LANG_CODE VARCHAR(2),
TEXT CLOB,
-- Legacy are To be able to cross check using columns - but not needed
LEGACY_TABLE VARCHAR(30) NOT NULL,
LEGACY_COLUMN VARCHAR(30) NOT NULL);
ALTER TABLE TRANSLATIONS
add CONSTRAINT UNIQUE_COMBINATION UNIQUE (DESCRIPTION_ENTITY, DESCRIPTION_COLUMN, KEY_OR_ID, LANG_CODE);
CREATE INDEX ind_description_entity ON TRANSLATIONS (DESCRIPTION_ENTITY);
CREATE INDEX ind_description_column ON TRANSLATIONS (DESCRIPTION_COLUMN);
CREATE INDEX ind_key_or_id ON TRANSLATIONS(KEY_OR_ID);
CREATE INDEX ind_lang_code ON TRANSLATIONS(LANG_CODE);
insert into TRANSLATIONS(DESCRIPTION_ENTITY, DESCRIPTION_COLUMN, KEY_OR_ID, LANG_CODE, TEXT, LEGACY_TABLE, LEGACY_COLUMN)
select 'LAW','TITLE', LAW_CODE, LANG_CODE, LAW_TITLE,
'LAW_TRANS','TITLE'
from LAW_TRANS where TITLE is not null;
Personally, I don't think there is anything wrong with not defining a relationship in a DB. At a massive investment bank where I was working before our Oracle specialists NEVER defined the relationships for performance reasons.
The basic question for your setup is, do you need a defined amount of languages or do you have to be flexible with adding languages later? If not, your approach is almost too flexible. Just adding different rows with the translation into the Laws table would be much more performant if you know you only every need 4 different languages.
Alternatively, you could just build a lock-up table:
original-string -> translated-string
And you can ignore the table name completely.

Foreign key limitations

I am wondering if a PL/SQL (oracle) table can carry three foreign keys? thanks in advance if any one can help me in this regard.
There is no explicit limit on the number of foreign keys on a table. However, there is a limit of 1000 columns per table, so that probably constitutes a practical limit.
Here is a SQL Fiddle which creates a toy table with five foreign keys.
There is not limit on foreign keys use except logic which based behind use of foreign keys, and if one table needs too much foreign keys, which is not logic wise, and database design suffers in such scenario.
As well as 1000-column constraint of oracle tables and pl/sql procedures also have limit in code.

How to generate PHYSICALLY sorted GUID as primary key in Oracle?

I'm trying to generate a sorted GUID as a primary key in Oracle. In SQL Server I could use one of the following to sort the rows physically
By clustered primary key as a unique identifier.
By NEWSEQUENTIALID.
I have searched for an Oracle equivalent but failed to find a solution. I know about Is there a way to create an auto-incrementing Guid Primary Key in an Oracle database?, but there's no indication whether SYS_GUID() is sorted.
How could I create a sequential primary key in Oracle?
If you want to create a GUID then SYS_GUID() is what you should be using, you can create this in a table as per the linked question. It's unclear from the documentation whether SYS_GUID() is incrementing. It might be but that's not really a statement that imparts trust.
The next part of your question (and some comments) keeps asking about clustered primary keys. This concept does not exist in the same way in Oracle as it does in SQL Server and Sybase. Oracle does have indexed organized tables (IOT) ...
... a table stored in a variation of a B-tree index structure... rows
are stored in an index defined on the primary key for the table. Each
index entry in the B-tree also stores the non-key column values. Thus,
the index is the data, and the data is the index.
There are plenty of uses for IOTs but it's worth bearing in mind you're altering the physical structure of the database on the disk for "performance reasons". You're doing the ultimate of all premature optimizations using something that has both negative and positive aspects. Read the documentation and be sure that this is what you want to do.
I would generally use an IOT only when you don't care about DML performance but when you do a lot of range scans, or you need to order by the primary key. You create an IOT in the same way as you would an ordinary table, but because everything you want is now part of the table everything goes in your table definition:
create table test_table (
id raw(32) default sys_guid()
, a_col varchar2(50)
, constraint pk_my_iot primary key (id)
) organization index;
It's worth noting that even with an IOT you must use an explicit ORDER BY in order to guarantee returned order. However, because of the way this is stored Oracle can table a few short cuts:
select *
from ( select *
from test_table
order by id )
where rownum < 2
SQL Fiddle.
As with everything, test, don't assume that this is the structure you want.
Oracle has as SYS_GUID() function, which generates a 16-byte RAW datatype. But, I'm not sure what you mean by "sorted GUID". Can you elaborate?
Do you mean you need each generated GUID to sort "after" the previously generated GUID? I looked at the SYS_GUID() function, and it seems to generate GUIDs in sorted order, but looking at the documentation, I don't see anything that says that is guaranteed.
If I understand your question correctly, I'm not sure it's possible.
You may be able to use SYS_GUID() and prepend a sequence, to get your desired sort order?
Can you explain more about your use case?
Adding the following in response to comment:
Ok, now I think I understand. What I think you want, is something called an IOT, or Index Organized Table, in Oracle. It's a table that has an index strucure, and all data is clustered, or grouped by the primary key. More information is available here:
http://docs.oracle.com/cd/E16655_01/server.121/e17633/indexiot.htm#CNCPT721
I think that should do what you want.

Does Oracle automatically create a secondary index for FOREIGN KEY columns?

I'm currenly developing on Oracle. I have several tables for which I defined FOREIGN KEY constraints. I have already read this SQL Server-oriented and this MySQL-oriented questions but I could find none about Oracle.
So the question is always the same: in order to optimize query performance, for those columns for which I create a FOREIGN KEY constraint, do I also have to create an explicit secondary index? Doesn't Oracle automatically create an index on FOREIGN KEYed columns to boost performances during JOINs?
I usually perform queries in which the WHERE clause compare against those columns.
No, Oracle doesn't automatically create indexes on foreign key columns, even though in 99% of cases you probably should. Apart from helping with queries, the index also improves the performance of delete statements on the parent table.

Resources