Как организовать хранение товаров-замен для оптимизации поиска?
Добрый день!
Есть элементы (товары), которые могут быть тождественными заменами друг для друга. Например, есть товар А, для него есть замены В и С. При поиске А должны выводиться его замены - В и С. Далее для товара В могут установлены замены D и E. При поиске А должны тогда выводиться B,C,D,E. Все замены тождественно равны друг для друга. Соответственно, при поиске C должны вывестись A,B,D,E.
Сейчас хранение замен организовано таблицей с 2 полями.
A - B
A - C
B - E
B - D.
Текущий алгоритм поиска сводится к рекурсивному выполнению поисковых запросов к БД. Например, для А вначале ищутся его замены. Затем для найденных замен ищутся их замены и тд. Затем все объединяется и выводится итоговый результат поиска. Это очень неоптимально, т.к. по каждой найденной замене делается еще запрос и тд. Т.е. куча запросов, а нужно получить нужные данные одним запросом.
Пробовали денормализацию данных, т.е. хранить все комбинации:
А - В
А - С
А - Е
А - D
B - A
B - C
B- D
B -E
C -A
...
Но тогда таблица разрастается до огромных размеров - сотни миллионов строк (в наших условиях). Плюс еще проблема, если удалить связь замены, например, между A и B, тогда получается E и D тоже перестают быть заменами для А и С, как их тогда убрать эти связи в денормализованной таблице не понятно.
Если замены двунаправлены независимо от уровня, то есть (по приведённому Вами примеру) A является заменой для E, то можно просто ввести ещё одно поле, которое будет одинаковым для всех товаров в одной группе замены. Что-то вроде связи многие-к-одному, но без дополнительной таблицы. Хотя никто не мешает ввести и дополнительную таблицу, чтобы дать имя группе замены.
Ну и, само собой, индекс по этому дополнительному полю.
Для правильного вопроса надо знать половину ответа
Тут надо смотреть, насколько часто меняется список замен. Если не часто, то держать две таблицы - основной набор, как у Вас сейчас, и кэшированный список вида ('A' - 'B,C,D,E'), перестраивая его при изменении основного набора.
Но тогда таблица разрастается до огромных размеров - сотни миллионов строк (в наших условиях).
и прекрасно. Все равно там только три инта хранится, не так ли?
При денормализации придется повесить на update любого товара тригер, который обновит закешированное значение.
При удалении товара, перелопатит все товары, в которых данный товар является заменителем