Not Just UNIQUE: Exclusion Constraints

7,213 views
7,022 views

Published on

Jeff Davis

UNIQUE 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!

1 Comment
6 Likes
Statistics
Notes
  • Thanks for this information. Hard to find much about the exclusion constraint.

    You use the 'period' datatype, which doesn't seem to exist. In your example, two column 'reservation' (timestamp) and 'duration' (interval) would be logical, or a start and end, both timestamps. I cannot figure out how to get the exclude constraint to work properly in this case.

    I see as of Postgesql 9.2 there are several range types, which come in handy for this functionality. But still, I would like how to use your example.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
7,213
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
24
Comments
1
Likes
6
Embeds 0
No embeds

No notes for slide

Not Just UNIQUE: Exclusion Constraints

  1. 1. Not just UNIQUE: Exclusion Constraints Jeff Davis Truviso, Inc.   1
  2. 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   2
  3. 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   3
  4. 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   4
  5. 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.) 5  
  6. 6. Almost... ● UNIQUE is almost what we need, but not  quite. ● Need something that can understand  “overlaps”   6
  7. 7. What's the Point? ● Very common business constraint known  as a “schedule conflict” ● Claims: – Existing solutions in SQL are bad...   7
  8. 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.   8
  9. 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?   9
  10. 10. Idea 1: Serialize ● Only one writer – Exclusive lock ● Before updating any reservation, search  all existing reservations for conflicts ● Horrible performance, availability  problems   10
  11. 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.   11
  12. 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...   12
  13. 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   13
  14. 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   14
  15. 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   15
  16. 16. Example CREATE TABLE reservation (   room      TEXT,   professor TEXT,   during    PERIOD,   EXCLUDE   USING gist     (room   WITH =,      during WITH &&) );   16
  17. 17. Example CREATE TABLE reservation (   room      TEXT,   professor TEXT,   during    PERIOD,   EXCLUDE   USING gist     (room   WITH =,      during WITH &&) ); Can be arbitrary expression of fields in table.   17
  18. 18. Example CREATE TABLE reservation (   room      TEXT,   professor TEXT,   during    PERIOD,   EXCLUDE   USING gist     (room   WITH =,      during WITH &&) ); Exclusion operator. In this case, “overlaps”.   18
  19. 19. Example CREATE TABLE reservation (   room      TEXT,   professor TEXT,   during    PERIOD,   EXCLUDE   USING gist     (room   WITH =,      during WITH &&) ); Type of index to build and use for  enforcement.   19
  20. 20. That was Easy ● 3 lines ● Scalable ● Flexible ● Declarative ● Robust ● Safe during concurrent INSERTs and  UPDATEs   20
  21. 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   21
  22. 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   22
  23. 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.   23
  24. 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.   24
  25. 25. Demo DEMO   25
  26. 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.   26
  27. 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!   27

×