Как организовать структуру хранения атрибутов?

Как в реляционной базе данных организовать структуру хранения атрибутов объектов для множества различных видов товаров и услуг: смартфоны, отели, фильмы и прочее? Атрибуты объектов невозможно вынести в отдельные столбцы, так как их слишком много.

Первый вариант - использовать noSQL возможности postgreSQL, то есть хранить значения атрибутов в виде json. Но возникает неприемлемая проблема с индексацией. GIN индексы работают на точное вхождение. Например:

SELECT
  *
FROM
  products
WHERE
  attributes @> '{"length": 10}'

но не работают на отбор по диапазону

SELECT
  *
FROM
  products
WHERE
 (attributes->>'length')::int4 > 10

В документации сказано, что для поиска по диапазону в jsonb поле, нужно создать Btree индекс для конкретного ключа JSON. Этот вариант не подходит, так как атрибутов очень много

Второй вариант, использовать паттерн EAV (объект - атрибут - значение). Здесь возникают сложности с различными типами данных и со сложносоставными условиями. Например, для 2,5 млн записей следующий запрос будет достаточно тяжелым

SELECT
  product_id
FROM 
  products_attributes
WHERE 
  attribute_id = 348612462852833281 AND value BETWEEN 1 AND 10

INTERSECT

SELECT
  product_id
FROM 
  products_attributes
WHERE 
  attribute_id = 348612464425861121 AND value BETWEEN 10 AND 20

INTERSECT

SELECT
  product_id
FROM 
  products_attributes
WHERE 
  attribute_id = 372655158259580929 AND value BETWEEN 20 AND 30

По отдельности каждый из трех запросов выполнится быстро благодаря Btree индексам. Но необходимость поиска пересечения по всем условиям сильно замедляет запрос.

Третий вариант - использовать noSql базу для хранения атрибутов. Но основные данные хранятся в реляционной базе и потребуется как-то передавать результат запроса из noSQL базы в запрос к реляционной базе. Передавать сотни тысяч идентификаторов объектов не лучшая идея.


Ответы (0 шт):