Last Updated: March 02, 2016
·
6.1K
· andersbrownwort

Index for uuid[] Array Data Type

PostgreSQL doesn't include an index type for uuid array columns.

Here's a table with a uuid array column:

CREATE TABLE items (
  things uuid[]
);

but when we try to create an index on it:

CREATE INDEX items_things_idx ON items USING GIN(things);
ERROR:  data type uuid[] has no default operator class for access method "gin"

so we must create an index type that understands how to compare elements in an array of UUIDs:

CREATE OPERATOR CLASS _uuid_ops DEFAULT FOR TYPE _uuid USING gin AS
      OPERATOR 1 &&(anyarray, anyarray),
      OPERATOR 2 @>(anyarray, anyarray),
      OPERATOR 3 <@(anyarray, anyarray),
      OPERATOR 4 =(anyarray, anyarray),
      FUNCTION 1 uuid_cmp(uuid, uuid),
      FUNCTION 2 ginarrayextract(anyarray, internal, internal),
      FUNCTION 3 ginqueryarrayextract(anyarray, internal, smallint, internal, internal, internal, internal),
      FUNCTION 4 ginarrayconsistent(internal, smallint, anyarray, integer, internal, internal, internal, internal),
      STORAGE uuid;

Now our index will create and SELECTs to items in the UUID array will be fast. For example, find all the rows that contain a particular UUID anywhere in the array:

SELECT * FROM items WHERE things @> ARRAY['a6e34e5d-b1fb-4240-8ad9-21ddf23134bb']::uuid[];

4 Responses
Add your response

This is awesome thank you.

over 1 year ago ·

Is there a way I can check if this operator has already been created? I want to include it in my migrations, but only execute the sql if the operator hasn't already been created.

over 1 year ago ·

IF EXISTS doesn't work for CREATE OBJECT so for that I was testing for duplicate object:

DO $$
  BEGIN

    -- -----------------------------------------------------
    -- New Index Type for uuid[] columns
    --
    -- Create a GIN inverted index type for UUID array
    -- columns to enable quick comparisons
    -- -----------------------------------------------------

    CREATE OPERATOR CLASS _uuid_ops DEFAULT FOR TYPE _uuid USING gin AS
      OPERATOR 1 &&(anyarray, anyarray),
      OPERATOR 2 @>(anyarray, anyarray),
      OPERATOR 3 <@(anyarray, anyarray),
      OPERATOR 4 =(anyarray, anyarray),
      FUNCTION 1 uuid_cmp(uuid, uuid),
      FUNCTION 2 ginarrayextract(anyarray, internal, internal),
      FUNCTION 3 ginqueryarrayextract(anyarray, internal, smallint, internal, internal, internal, internal),
      FUNCTION 4 ginarrayconsistent(internal, smallint, anyarray, integer, internal, internal, internal, internal),
      STORAGE uuid;

  EXCEPTION
    WHEN duplicate_object THEN
      RAISE NOTICE 'error: %', SQLERRM;
  END;
$$;
over 1 year ago ·

Excellent, thank you. I tried the IF EXISTS, and it didn't work, then chased my tail trying to find the negative version. Catching the exception with duplicate_object works well. Really appreciative of your help. Happt New Year!

over 1 year ago ·