0

I have 3 enum() columns with the same option values inside.
I first tried to use the "set" datatype which originally was meant to do that (hold multiple values from a set) but it seems that datatype isn't managed for 15+ years and isn't even supporting an index.
Is there a nice way to index those 3 columns so I can use them in searched without destroying query performance ?

SELECT * FROM TABLE WHERE a='x' OR b='x' OR c='x'

I thought about creating a virtual field which uses a boolean logic (&) on the 3 enum field-numbers and combines them into a large number but that's quite a hack and not nice to maintain.

Has someone solved this sort of task elegantly ? (I do not want to use a support table and JOIN it, I want to stay with a single table)

Paul White
95.4k30 gold badges440 silver badges689 bronze badges
asked Dec 13, 2020 at 0:28
1
  • Slightly off topic, but` 'x' in (a, b, c)` Is a bit shorter. Commented Dec 13, 2020 at 5:05

3 Answers 3

1

UNION

You have listed most of the approaches. Here's one more:

SELECT ... WHERE a='x'
UNION ALL
SELECT ... WHERE b='x'
UNION ALL
SELECT ... WHERE c='x'

And have separate (not composite) indexes:

INDEX(a), INDEX(b), INDEX(c)

Each SELECT will efficiently use one of the indexes. Then the UNION will combine the results.

Use UNION DISTINCT if you expect dups and need to remove them.

that datatype isn't managed for 15+ years

Yeah, SET has been stable for a long time (more than 20 years). I tend to use some sized INT together with boolean operators instead of SET. But a table scan is needed in either case.

How big is your table? 1000 rows is hardly worth worrying about performance on.

FULLTEXT

Even faster (in some situations):

FULLTEXT(a, b, c)
WHERE MATCH(a, b, c) AGAINST('+x' IN BOOLEAN MODE)

(No OR, no UNION, etc.) If Fulltext is applicable, this will be very fast.

answered Dec 13, 2020 at 2:41
2
  • 1.5 billion rows ;/ Commented Dec 18, 2020 at 2:59
  • @John -- OK, there's another way. Commented Dec 18, 2020 at 3:29
0

Because you need to use OR logic in your WHERE predicate, there's not a way to create one index that covers every case unfortunately.

Fortunately you're basically on the money with a virtual field or rather you should create a generated column, and then you can create an index on that single column so your queries are performant.

answered Dec 13, 2020 at 0:56
1
  • Yes, I'm quite sure there is a way to generate a generated column though I've not seen examples of that anywhere. Given that 1 enum seems to have a 16 bit key a 64 bit number can hold 4 enums, so with some shifting it should be posible to create 1 large number out of my 3 enums. Though I don't exactly know how to do it in mysql, also querying for it sounds difficult I've the feeling this will be a major pain to maintain Commented Dec 18, 2020 at 3:00
0

There's a reason why set isn't managed anymore/not supporting an index: It's essentially just a bitwise representation for a set to minimize memory usage.

However, an index on a set column supporting performant set operations would require multiple indexes in the background for each every, as if one would just make a boolean column for each possible set entry and then made a separate index per column (to make checking if a value is in the set fast), and also possibly other indexes of column combinations.

All in all this would no longer be space efficient and the expected performance for filtering by the set/writing to the column would be easily comprehensible.

You're better off making separate boolean columns or another table with 1:n relationship and define the indexes the way you need them because a catch all set index would be too costly to maintain in most cases

answered Dec 13, 2020 at 14:27

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.