Оптимизация MySQL при фильтрации пар ключ-значение в виде записей - PullRequest
3 голосов
/ 31 июля 2011

У меня есть структура БД, которая предназначена для хранения атрибутов для конкретных объектов в легко расширяемом виде.
Существует таблица «Объекты».

+----+----------------------
| id | ....(name, type, etc)
+----+----------------------

Далее у меня естьТаблица «Атрибуты».

+----+------+
| id | Name |
+----+------+

И, наконец, таблица «Отношения», используемая для хранения всех данных в виде пар атрибут-объект (в качестве первичного ключа) с соответствующими значениями.

+--------+---------+-------+
| id_obj | id_attr | value |
+--------+---------+-------+

Мне нужно получить идентификаторы для объектов, которые удовлетворяют нескольким условиям одновременно.Например, у меня есть атрибуты с именами «Тип» и «Город», и мне нужно выбрать идентификаторы для объектов, где соответствующие значения для этих атрибутов - «Квартира» и «Город b».

Лучшее решениеМне удалось придумать после того, как со вчерашнего дня ударился головой о стену (ну, единственное, что хорошо в этом запросе, - это то, что он действительно работает и выбирает необходимые записи):объем хранимых данных может потенциально стать несколько большим, и я боюсь, что все эти подзапросы (может потребоваться указать около 10-15 фильтров), каждый из которых анализирует всю БД, могут вызвать серьезные проблемы с производительностью (не говоря уже о том, чтодаже с моими ограниченными навыками SQL я уверен, что должен быть лучший способ сделать то, что мне нужно).
С другой стороны, радикальные изменения в БД на самом деле не вариант, так как код, работающий сэто сильно зависит от текущей структуры БД.
Есть ли способ проверить атрибуты так, как мне нужно, в грехеgle запрос, с ограниченным количеством или без изменений в структуре хранимых данных?


Рабочий запрос, эквивалентный приведенному выше, но гораздо лучше оптимизированный, кредитует DRapp :

SELECT STRAIGHT_JOIN
      rel.id_obj
   from 
      relations rel
         join attributes atr
            on rel.id_attr = atr.id
   where 
         ( rel.value = 'Apartment' AND atr.name = 'Type'  )
      or ( rel.value = 'City b' AND atr.name = 'City' )
   group by 
      rel.id_obj
   having
      count(*) = 2
   limit
      0, 20

1 Ответ

4 голосов
/ 31 июля 2011

Это должно дать вам то, что вам нужно ... Каждое из условий «И», где вы можете просто добавить в качестве квалифицированного элемента.Затем просто измените предложение «Имея», чтобы оно соответствовало тому же числу, что и критерии, которые вы разрешаете ... Сначала я поместил таблицу отношений, так как в ней было бы меньшее совпадение с набором «Значения» города или значений типа.Убедитесь, что у вас есть индекс для таблицы отношений в столбце «VALUE».

SELECT STRAIGHT_JOIN
      rel.id_obj
   from 
      relations rel
         join attributes atr
            on rel.id_addr = atr.id
   where 
         ( rel.value = 'Apartment' AND atr.name = 'Type'  )
      or ( rel.value = 'Some City' AND atr.name = 'City' )
   group by 
      atr.id_obj
   having
      count(*) = 2
   limit
      0, 20

Если вы хотите получить все фактические данные объекта из этого результата, вы должны обернуть его примерно так ...

select obj.*
   from 
      ( complete SQL statement above ) PreQuery
         join Object obj on PreQuery.id_obj = obj.id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...