У магазинов настройки лежат в jsonb-колонке settings, ключей штук сорок. Теперь надо часто искать магазины с включённой курьерской доставкой: where("settings ->> 'courier' = 'true'"). Магазинов 300 тысяч, запрос около 600 мс. Индексировать jsonb или пора выносить горячие ключи в обычные колонки?
Если ключ нужен в фильтрах постоянно, я бы вынес его в обычную boolean-колонку: индекс проще, тип настоящий, валидации нормальные. Если пока не хочется, есть два варианта индекса. По выражению под конкретный ключ, частичный:
CREATE INDEX CONCURRENTLY index_shops_on_courier
ON shops ((settings ->> 'courier'))
WHERE settings ->> 'courier' = 'true';
Или общий GIN по всей колонке, тогда искать надо оператором вхождения:
Shop.where("settings @> ?", { courier: true }.to_json)
GIN с jsonb_path_ops компактнее, но умеет только @>. Для одного-двух горячих ключей первый вариант лучше, для поиска по любым ключам второй. Пришлите потом EXPLAIN ANALYZE до и после.