I have a table with a unique constraint, where a, b and c are all nullable:
ALTER TABLE public.t1 ADD CONSTRAINT unique_ids UNIQUE (a, b, c);
Then I inserted two records, deliberately leaving b as null :
insert into t1 (a,c) values ('test', '12312');
insert into t1 (a,c) values ('test', '12312');
I expect that the unique constraint has been violated, but apparently Vertica doesn't think so because the following returns nothing:
SELECT ANALYZE_CONSTRAINTS('t1');
How can I enforce a unique constraint across multiple (nullable) columns in Vertica?
I'd have to consult the documentation for a final answer, but I'm pretty sure that Vertica doesn't enforce constraints during an insert. It has to do with optimizations.
I always enforced uniqueness in my ETL framework if I required it.
Also, if I was doing a large amounts of aggregations as my output, I didn't worry about a few dupes here and there. Maybe that's bad form, but a few entries out of billions didn't worry me.
Related
I'm trying to make sure I'm getting the benefit of selecting from a partition when using reference partitions.
In normal partitions, I know you have to include the column(s) on which the partition is defined in order for Oracle to know it can just search one specific partition.
My question is, when I'm selecting from a reference-partitioned table, do I just need to include the column on which the reference foreign key is defined? Or do I need to join and include the parent table's column on which the partition is actually defined?
create table alpha (
name varchar2(240) not null,
partition_no number(14) not null,
constraint alpha_pk
primary key (name),
constraint alpha_c01
check (partition_no > 0)
)
partition by range(partition_no)
interval (1)
(partition empty values less than (1))
;
create table beta (
name varchar2(240) not null,
alpha_name varchar2(240) not null,
some_data number not null,
constraint beta_pk
primary key (name),
constraint beta_f01
foreign key (alpha_name)
references alpha (name)
)
partition by reference (beta_f01)
;
Assume the tables in production will have much more data in them, with hundreds of millions of rows in the beta table, but merely thousands per partition.
Is this all I need?
select b.some_data
from beta b
where b.alpha_name = 'Blah'
;
Thanks if anyone can verify this for me. Or can explain anything else I'm missing with regard to properly creating indexes in reference-partitioned tables.
[Edit] Removed part of the example where clause that shouldn't have been there. The example is meant to represent reading the reference-partitioned with just the reference partition foreign key in the where clause.
So a table I am looking at has a unique constraint AND a unique index over multiple columns, and the exact same columns for both.
Is there a use for this or is the unique constraint redundant?
I agree that the existence of unique constraints and unique indexes does look redundant at first. It seems like a violation of Don't Repeat Yourself, allowing for confusing differences. But there are at least two reasons both exist - management features and allowing existing duplicates.
Management Features
In theory, a logical constraint can be created without worrying about the implementation. The constraint specifies what must be true, along with some options such as deferring the constraint until a commit.
In practice, constraints have such a large performance and storage penalty that the implementation must be considered. An index is required or else a single insert would require O(n) time instead of O(log(n)). Those indexes can take up a huge amount of space; someone might want to specify where it's stored, how it's compressed, etc.
Most of the time those features aren't important and using all the index defaults is fine. But sometimes storage and performance are critical and people will want to tweak the index without caring about the constraint.
Allow Existing Duplicates
There is at least one case where a unique constraint does not have a unique index. It's possible to allow existing duplicate valuess but prevent any future duplicates by setting the constraint to NOVALIDATE and using a non-unique index.
--Create table and insert duplicate values.
create table test1(a number);
insert into test1 values(1);
insert into test1 values(1);
commit;
--Add a non-validated unique constraint, with a non-unique index.
alter table test1
add constraint test1_uq unique(a)
using index (create /* Not unique!*/ index test1_uq on test1(a)) novalidate;
--Now multiple inserts raise: ORA-00001: unique constraint (JHELLER.TEST1_UQ) violated
insert into test1 values(2);
insert into test1 values(2);
The physical index must allow duplicates, but the logical constraint knows to not allow any more duplicates. Although this is a rare feature and I'm not sure if I've ever seen it in production code.
I have a parent table containing the following columns:
- PARENT_ID: UUID
- EVENT_DATE: TIMESTAMP
- DATA_COLUMN1: VARCHAR2(255)
- DATA_COLUMN2: VARCHAR2(255)
The table is range partitioned by EVENT_DATE. Data is only retained for a month and the last partition is dropped on a daily basis.
Following my understanding, using a global index for PK would result in sub-standard performance when dropping a partition. This means that the PK of this table has to be based on both PARENT_ID + EVENT_DATE in order to create a local index.
I have a second table that is the child of the first (via one-to-many relationship). It has the following columns:
- CHILD_ID: UUID
- PARENT_ID: UUID - FK into parent table
- DATA_COLUMN3: VARCHAR2(255)
- DATA_COLUMN4: VARCHAR2(255)
To partition the child table, I decided to use reference partitioning. One of its big advantages: it removes the need to duplicate the partition key in the child table. However, based on my reasoning, the only way to achieve this is through global indexes. Here is my train of thought:
For the unique index of the parent table to be local, the PK must include the partition key, e.g. EVENT_DATE.
A foreign key constrain cannot reference only part of the PK. Thus the child table must include both PARENT_ID and EVENT_DATE columns.
What's more, I also read that "When using reference partitioning, most child table indexes
should be defined as global, unless there is a compelling reason
for a given index to be defined as local." (http://www.nocoug.org/download/2010-05/Zitelli-Reference_Partitioning_NoCOUG.pdf).
Am I missing something or is there no way to use reference partitioning without having global indexes or duplicating data?
An explanation on how reference partitioning works with local/global indexes will be much appreciated!
You understand correctly. if you want to create a reference partition you need to define a valid FK. in your case - both parent_id and event_id needs to be present in the child table.
Ref partitions are for cases when you want to partition a table according to a column not in the PK those not in the child table. this is not your case - you can apply range partition on both tables and gain max pruning.
The event_date in the child table is not redundant - it's required by the model - you need data_columns 3/4 in the child table for each instance of parent_id + event_date.
Regarding the local indexes on a child table in a ref partitioned table - my logic say exactly the opposite. if i have a ref partition i'm aiming at max pruning which means that i want as less partitions as possible to be accessed in each query. in this case i would want local indexes and not global.
You said "using a global index for PK would result in sub-standard performance when dropping a partition". when you drop a partition from the table all global indexes will be invalidated and you will have to rebuild them. this is the only performance impact regarding DDL changes. PK on a partitioned table must be global so you don't have a choice here any way.
Though above answer has been answered but on you thought: 'A foreign key constrain cannot reference only part of the PK. Thus the child table must include both PARENT_ID and EVENT_DATE columns.'
I believe FK can refer to part of PK if your attribute has been defined with Unique constraint & I see that possible in your example.
Example:
Table A ( orderid, orderdate, custid)
PF -> OrderID, OrderDate
Table B(OrderID, ItemID)
In table B, orderID can be FK if OrderID is defined as Unique in Table A.
I hope this helps.
We have deadlock issue in Oracle 11.2g. One potential reason why deadlock occurs is deleting from child table locks parent table. I searched from oracle documentations, and did't find any specification this kind of lock. Any explanation or reference of documentation would be greatly appreciated.
Here is the code.
CREATE TABLE table_parent (a NUMBER PRIMARY KEY);
CREATE TABLE table_child (b NUMBER, a NUMBER,PRIMARY KEY (b), CONSTRAINT fk_relation FOREIGN KEY (a) REFERENCES table_parent(a));
INSERT INTO table_parent VALUES (1);
INSERT INTO table_parent VALUES (2);
INSERT INTO table_child VALUES (1,1);
INSERT INTO table_child VALUES (2,1);
INSERT INTO table_child VALUES (3,1);
INSERT INTO table_child VALUES (4,1);
COMMIT;
Then delete 1 record from child table.
DELETE FROM table_child WHERE b=4;
When we look V$LOCK table before executing commit. There is two new lock that 'table_child' and 'table_parent' in type of 'TM'.
Here is the query to look V$LOCK table.
SELECT O.OWNER, O.OBJECT_ID, O.OBJECT_NAME, O.OBJECT_TYPE, L.TYPE
FROM DBA_OBJECTS O, V$LOCK L
WHERE O.OBJECT_ID = L.ID1;
The question is why 'table_parent' has been locked?
For maintaining constraints that 'span multiple rows', which is the case for a foreign key, there are moments when one (ie. the DBMS) needs to serialize transactions. The moments at which serialization is required depend one-on-one on the type of changes that a transaction performs on the involved tables. Theoretically (in a DBMS that offers snapshot isolation, which is what Oracle does), only if the type of change is such that it could potentially violate the multi-row constraint, would the DBMS need to automatically serialize transactions (for instance by acquiring various types of locks).
Now in the case of a foreign key, one needs to ask oneself: when can a foreign key be violated? There are four scenarios.
a parent row is deleted: will violate FK if child-rows still exist.
a parent row's key is updated: will violate FK if child-rows till 'point to' old value of key.
a child row is inserted: will violate FK if row points-to non-existent parent-row.
a child row's fk-column value is updated: will violate FK if new column value points to non-existent parent-row.
All other types of transactions on the (2) tables involved can never violate the FK. So in your case, a child row is deleted, no serialization should be necessary. However Oracle probably has some 'implementation specific' reason, which forces it to do acquire some kind of lock.
I've seen a different scenario where Oracle performs this kind of "unnecessary" locking too: you can find it here https://forums.oracle.com/forums/thread.jspa?messageID=10050753�
Toon
Add an index on the table_child(a) column -- you always index foreign key columns for just this reason.
An answer to this is explained with examples here http://www.oraclebin.com/2012/12/what-is-deadlock-in-oracle.html
Could someone clarify what is the purpose of having unique index without unique constraint (Oracle)?
For example,
create table test22(id int, id1 int, tmp varchar(20));
create unique index idx_test22 on test22(id);
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // ok
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // fails, ORA-00001: unique
// constraint (TEST.IDX_TEST22) violated
So far it looks like there is a constraint. But
create table test33(id int not null primary key,
test22_id int not null,
foreign key(test22_id) references test22(id) );
also fails with "ORA-02270: no matching unique or primary key for this column-list".
I'm totally confused by this behaviour. Is there a constraint or not?
There are many articles that explain why it's possible to have a unique constraint without unique index; that is clear and makes perfect sense. However, I don't understand the reason for unique index without constraint.
A constraint and an index are separate logical entities. A unique constraint, for example, is visible in USER_CONSTRAINTS (or ALL_CONSTRAINTS or DBA_CONSTRAINTS). An index is visible in USER_INDEXES (or ALL_INDEXES or DBA_INDEXES).
A unique constraint is enforced by an index though it is possible (and sometimes necessary) to enforce a unique constraint using a non-unique index. A deferrable unique constraint, for example, is enforced using a non-unique index. If you create a non-unique index on a column and subsequently create a unique constraint, you can also use that non-unique index to enforce the unique constraint.
In practice, a unique index acts very much like a unique, non-deferrable constraint in that it raises the same error that a unique constraint raises since the implementation of unique constraints uses the index. But it is not quite the same because there is no constraint. So, as you've seen, there is no unique constraint so you cannot create a foreign key constraint that references the column.
There are cases where you can create a unique index that you cannot create a unique constraint. A function-based index, for example, that enforces conditional uniqueness. If I wanted to create a table that supported logical deletes but ensure that COL1 is unique for all non-deleted rows
SQL> ed
Wrote file afiedt.buf
1 CREATE TABLE t (
2 col1 number,
3 deleted_flag varchar2(1) check( deleted_flag in ('Y','N') )
4* )
SQL> /
Table created.
SQL> create unique index idx_non_deleted
2 on t( case when deleted_flag = 'N' then col1 else null end);
Index created.
SQL> insert into t values( 1, 'N' );
1 row created.
SQL> insert into t values( 1, 'N' );
insert into t values( 1, 'N' )
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.IDX_NON_DELETED) violated
SQL> insert into t values( 1, 'Y' );
1 row created.
SQL> insert into t values( 1, 'Y' );
1 row created.
But if we're talking about a straight unique non-function based index, there are probably relatively few cases where it really makes more sense to create the index rather than creating the constraint. On the other hand, there are relatively few cases where it makes much difference in practice. You'd almost never want to declare a foreign key constraint that referenced a unique constraint rather than a primary key constraint so you rarely lose something by only creating the index and not creating the constraint.
As was already explained in other answers: constraints and the indexes are different entities. But they lack precise definitions and official comments on the topic. Before we discuss the relationship between these two entities lets take a look at their purpose independent of each other.
Purpose of a constraint1:
Use a constraint to define an integrity constraint-- a rule that restricts the values in a database.
The purposes of an index2:
You can create indexes on columns to speed up queries. Indexes provide faster access to data for operations that return a small portion of a table's rows.
In general, you should create an index on a column in any of the following situations:
The column is queried frequently.
A referential integrity constraint exists on the column.
A UNIQUE key integrity constraint exists on the column.
Now we know what constraints and indexes are, but what is the relationship between them?
The relationship between indexes and constraints is3:
a constraint MIGHT create an index or use an existing index to efficient enforce itself. For example, a PRIMARY KEY constraint will either create an index (unique or non-unique depending) or it will find an existing suitable index and use it.
an index has nothing to do with a constraint. An index is an index.
So, a constraint MIGHT create/use and index. An INDEX is an INDEX, nothing more, nothing less.
So sum this up and directly address the following sentence from your question:
However, I don't understand the reason for unique index without constraint.
Indexes speed up queries and integrity checks (constraints). Also for conditional uniqueness a unique (functional) index is used as this cannot be achieved with a constraint.
Hopefully this brings a little bit more clarification to the whole topic, but there is one aspect of the original question that remains unanswered:
Why did the following error occur when no constraint existed:
ORA-00001: unique constraint (TEST.IDX_TEST22) violated
The answer is simple: there is no constraint and the error message misnames it!
See the official "Oracle Ask TOM" comment 4 on the same problem:
It isn't a constraint. the error message "misnames" it.
If it were a constraint, you could create a foreign key to it -- but you cannot.
Hope it helps.
Links:
1 Oracle 10g Documentation on Constraints
2 Oracle 10g Documentation on Selecting an Index Strategy
3 4 "Oracle Ask TOM" answer to a similar problem
Another point which may be useful in this context is :
Disabling/Dropping an existing unique constraint do not drop the underlying unique index. You got to drop the unique index explicitly.
You can not make conditional uniqueness by declaring a unique constraint, But you can do it by declaring a unique index.
Supporse if you try to execute below:
alter table test22
add constraint test22_u
unique (id, case when tmp = 'aaa' then null else tmp end);
ORA-00904: : invalid identifier
But if you can do it by using the unique index
create unique index test22_u
on test22 ( customer_id,
case when is_default = 'Y' then null else address_id end)