MySQL Query faster alternative to DISTINCT and REGEXP

You might get faster performance using FIND_IN_SET and a couple of joins:

SELECT DISTINCT locations.*
FROM locations
INNER JOIN users users_include ON
  users_include.user_id = 1      
  AND FIND_IN_SET(users_include.user_locations, locations.combined_locations) > 0
  AND users_include.user_selection = 'Yes'
LEFT JOIN users users_exclude ON
  users_exclude.user_id = 1
  AND FIND_IN_SET(users_exclude.user_locations, locations.combined_locations) > 0
  AND users_exclude.user_selection = 'No'
WHERE users_exclude.user_id IS NULL

Note that the logic implemented here is “at least one location with user_selection = ‘Yes’ and no location with user_selection = ‘No'” – I think this is the same as the logic implemented by your query.

If the logic instead should be “all locations with user_selection = ‘Yes’ and no location with user_selection = ‘No'”, that can be accomplished with a GROUP BY clause and a HAVING clause (with a count):

SELECT locations.*
FROM locations
INNER JOIN users users_include ON
  users_include.user_id = 1
  AND FIND_IN_SET(users_include.user_locations, locations.combined_locations) > 0
  AND users_include.user_selection = 'Yes'
LEFT JOIN users users_exclude ON
  users_exclude.user_id = 1
  AND FIND_IN_SET(users_exclude.user_locations, locations.combined_locations) > 0
  AND users_exclude.user_selection = 'No'
WHERE users_exclude.user_id IS NULL
GROUP BY locations.id, locations.column1, locations.column2, locations.combined_locations
HAVING (1 + CHAR_LENGTH(combined_locations) - CHAR_LENGTH(REPLACE(combined_locations, ',', ''))) = COUNT(users_include.user_id)

Read more here: Source link