For a system we're building, we store discount codes as strings in a Postgres table. We have a system where we support multiple workspaces that share the same database, and have a special value ('*'
) that is used as a wildcard.
For discount codes, we store the following information:
CREATE TABLE discount_codes
id uuid PRIMARY KEY
, workspace_id character varying
, code character varying
, case_sensitive bool
);
Sometimes we have to generate thousands of codes to be exported to external systems, where they can be sent out in e-mails and such. When generating these codes, we need to check if none of the codes overlap.
Currently, when inserting a code, we query existing codes like this:
The new discount code is case sensitive:
SELECT
COUNT(*)
FROM
discount_codes
WHERE
(
workspace_id = '*' OR
workspace_id = :workspaceId
) AND
(
(
LOWER(code) = LOWER(:code) AND
case_sensitive = false
) OR (
code = :code AND
case_sensitive = true
)
)
The new discount code is not case sensitive:
SELECT
COUNT(*)
FROM
discount_codes
WHERE
(workspace_id = '*' OR workspace_id = :workspaceId) AND
LOWER(code) = LOWER(:code)
If this query returns a count of more than 0, we know that there is a collision.
I would like to know if it would be useful to create an index on the length of the code
, so that we can filter out all rows where code
has a different length. We're talking about hundred thousands of codes being present in the database. If it would help, how would I create an index like this?
During bulk generation, I would like to generate 1000 codes at a time, and query the database to see if there is overlap with any of these codes. Would it be better to do this per 100 codes, or per 10000 codes?
explain(analyze, verbose, buffers, settings)
to get the query plan and see where the time is spent. And you can create an index on LOWER(code):CREATE INDEX idx_ discount_codes_lower_code ON discount_codes(LOWER(code));