not just unique: exclusion constraints

27
 1 Not just UNIQUE: Exclusion Constraints Jeff Davis Truviso, Inc.

Upload: command-prompt-inc

Post on 19-May-2015

6.143 views

Category:

Documents


2 download

DESCRIPTION

Jeff DavisUNIQUE indexes have long held a unique position among constraints: they are the only way to express a constraint that two tuples in a table conflict without resorting to triggers and locks (which severely impact performance). But what if you want to impose the constraint that one person can't be in two places at the same time? In other words, you have a schedule, and you want to be sure that two periods of time for the same person do not overlap. This is nearly impossible to do efficiently with the current version of PostgreSQL -- and most other database systems. I will be presenting Exclusion Constraints, which has been accepted for the next PostgreSQL release, along with the PERIOD data type (available now from PgFoundry). I will show how these can, together, offer a fast, scalable, and highly concurrent solution to a very common business requirement. A business requirement is still a requirement even if your current database system can't do it!

TRANSCRIPT

Page 1: Not Just UNIQUE: Exclusion Constraints

  1

Not just UNIQUE:Exclusion Constraints

Jeff DavisTruviso, Inc.

Page 2: Not Just UNIQUE: Exclusion Constraints

  2

Schedule Conflict

● One person can't be in two places at the same time

● Two people can't use an exclusive resource at the same time

● Business constraint● Just one instance of an interesting class 

of problems

Page 3: Not Just UNIQUE: Exclusion Constraints

  3

PERIOD Type

● Need a concept of a period of time, otherwise the system doesn't know what a “schedule conflict” is

● PERIOD data type:– http://pgfoundry.org/projects/temporal

● Definite beginning and end time, e.g., the period of time during which a professor is teaching in a classroom

Page 4: Not Just UNIQUE: Exclusion Constraints

  4

Constraints

● Foreign Key– Requires another tuple to exist

● CHECK Constraint– Only looks inside one tuple, can't compare 

two tuples– You can subvert the system by using a 

UDF● Race conditions

Page 5: Not Just UNIQUE: Exclusion Constraints

  5

Why is UNIQUE so unique?

● Only constraint where two tuples can conflict with eachother

– If x = 5 in one tuple, there can be no other tuple where x = 5

● Effectively a predicate lock on a very simple predicate

– Transactions wait on other transactions trying to insert the same value

● Special code path inside Btree to enforce uniqueness (doesn't work for GiST, etc.)

Page 6: Not Just UNIQUE: Exclusion Constraints

  6

Almost...

● UNIQUE is almost what we need, but not quite.

● Need something that can understand “overlaps”

Page 7: Not Just UNIQUE: Exclusion Constraints

  7

What's the Point?

● Very common business constraint known as a “schedule conflict”

● Claims:– Existing solutions in SQL are bad...

Page 8: Not Just UNIQUE: Exclusion Constraints

  8

What's the Point?

● Very common business constraint known as a “schedule conflict”

● Claims:– Existing solutions in SQL are bad...– ...except Exclusion Constraints in 

PostgreSQL 9.0.

Page 9: Not Just UNIQUE: Exclusion Constraints

  9

Non­Overlapping Constraint

● Let's look at existing solutions for schedule conflicts

● How do you specify a non­overlapping constraint in an SQL system?

– Any SQL system?

● Ideas?

Page 10: Not Just UNIQUE: Exclusion Constraints

  10

Idea 1: Serialize

● Only one writer– Exclusive lock

● Before updating any reservation, search all existing reservations for conflicts

● Horrible performance, availability problems

Page 11: Not Just UNIQUE: Exclusion Constraints

  11

Idea 2: Quantize

● Break into time slices, e.g. 1 hour.● Use UNIQUE constraint on beginning● Imposes unnecessary business constraint

– Nobody can reserve 1:30pm – 2:30pm

● Code is not reusable for other businesses– Hotels reserve by day

● Not useful when quantum is too small– Security, scientific apps, audit logs, etc.

Page 12: Not Just UNIQUE: Exclusion Constraints

  12

Idea 3: Procedural Code

● Triggers● Perhaps use dummy rows that exist only 

for row­level locks● Perhaps application code● Probably will not perform well● Very business­specific, not reusable● Error prone● Good luck...

Page 13: Not Just UNIQUE: Exclusion Constraints

  13

Idea 4: Delayed Check

● Record timestamp when reservation was recorded

● Make extra process check for conflicts and notify victims asynchronously

● Unhappy customers● Adds uncertainty after “commit”● Cascading problem

Page 14: Not Just UNIQUE: Exclusion Constraints

  14

Back to the Example

● If the constraint is not enforced by the DBMS...

● ...then it will be enforced when two professors each believe they have reserved the same room

● A duel?● Probably a less desirable constraint 

enforcement mechanism than a friendly error from the DBMS

Page 15: Not Just UNIQUE: Exclusion Constraints

  15

Exclusion Constraints

● New feature in 9.0● Not constraint_exclusion!● Offers constraint enforcement mechanism 

more general than UNIQUE● Declarative● Scalable

– Performance comparable to UNIQUE

Page 16: Not Just UNIQUE: Exclusion Constraints

  16

Example

CREATE TABLE reservation(  room      TEXT,  professor TEXT,  during    PERIOD,  EXCLUDE   USING gist    (room   WITH =,     during WITH &&));

Page 17: Not Just UNIQUE: Exclusion Constraints

  17

ExampleCREATE TABLE reservation(  room      TEXT,  professor TEXT,  during    PERIOD,  EXCLUDE   USING gist    (room   WITH =,     during WITH &&));

Can be arbitrary expression of fields in table.

Page 18: Not Just UNIQUE: Exclusion Constraints

  18

ExampleCREATE TABLE reservation(  room      TEXT,  professor TEXT,  during    PERIOD,  EXCLUDE   USING gist    (room   WITH =,     during WITH &&));

Exclusion operator. In this case, “overlaps”.

Page 19: Not Just UNIQUE: Exclusion Constraints

  19

ExampleCREATE TABLE reservation(  room      TEXT,  professor TEXT,  during    PERIOD,  EXCLUDE   USING gist    (room   WITH =,     during WITH &&));

Type of index to build and use for enforcement.

Page 20: Not Just UNIQUE: Exclusion Constraints

  20

That was Easy

● 3 lines● Scalable● Flexible● Declarative● Robust● Safe during concurrent INSERTs and 

UPDATEs

Page 21: Not Just UNIQUE: Exclusion Constraints

  21

Operator Detects Conflicts

● The operator is used to search for conflicts

● Should return TRUE when two values conflict

● For example, the “overlaps” operator (“&&”) would be used to enforce the constraint that no two tuples contain overlapping values

Page 22: Not Just UNIQUE: Exclusion Constraints

  22

Back to UNIQUE

● If you specify all operators as “=”, the semantics are identical to UNIQUE

● Performance slightly worse, because one additional index search is required

● Can be used with GiST or Hash indexes

Page 23: Not Just UNIQUE: Exclusion Constraints

  23

UNUNIQUE

● If you specify the operator as “<>”, then constraint is the opposite of UNIQUE: all values must be the same!

● Use case: At the zoo, if you've already put zebras in the cage, you can put more zebras in ­­ but don't put lions in.

Page 24: Not Just UNIQUE: Exclusion Constraints

  24

Multi­Column Constraints

... EXCLUDE USING gist      (a WITH =,       b WITH &&) ...

Tuple1 conflicts with Tuple2 if and only if:Tuple1.a =  Tuple2.a AND

Tuple1.b && Tuple2.b

Otherwise, both tuples can appear in the table.

Page 25: Not Just UNIQUE: Exclusion Constraints

  25

Demo

DEMO

Page 26: Not Just UNIQUE: Exclusion Constraints

  26

Extra Capabilities

● Support for predicates (WHERE)● Constraint on a subset of the table

● Support for arbitrary expressions:... EXCLUDE ((t::circle)    WITH &&) ...

● Deferrable● Doesn't work with GIN, yet.

Page 27: Not Just UNIQUE: Exclusion Constraints

  27

Conclusion

● Constraints are always enforced● Sometimes by the DBMS (cheap), 

sometimes by real life (expensive)● The very simple, very common “schedule 

conflict” constraint is almost impossible to enforce with most DBMSs

● Let's make it easy, scalable, and flexible.● “Exclusion Constraints” in 9.0!