My task is to find business objects which are exactly same as given object (ones which have exactly same set of properties with exactly same values). Performance is critical.
Подход может варьироваться в зависимости от среднего числа свойств, которые обычно имеют объекты, от нескольких до десятков.
Предполагая, что объекты имеют различное количество свойств:
Я бы начал с составного неуникального индекса на диаде (PropertyValues.PropertyId, PropertyValues.PropertyValue) для select-performance.
Затем, учитывая идентификатор сущности, я бы выбрал в курсоре его свойства - пары свойств-значений.
[EDIT:
Не уверен, является ли (entityid, propertyid) уникальным в вашей системе или вы разрешаете несколько экземпляров одного и того же идентификатора свойства для сущности, например, FavoriteColors:
entityid propertyid property value
1 17 blue
1 17 dark blue
1 17 sky blue
1 17 ultramarine
Вам также потребуется либо неуникальный индекс для монады (PropertyValues.entityid), либо составной индекс для (PropertyValues.entityid, PropertyValues.propertyid); составной индекс будет уникальным, если вы хотите, чтобы один и тот же идентификатор свойства не связывался с сущностью более одного раза.
Если свойство может встречаться несколько раз, вероятно, в вашей таблице свойств должен быть флаг CanBeMultivalued. Если вы хотите предотвратить это, у вас должен быть уникальный индекс триады (entityid, propertyid, propertyvalue):
entityid propertyid property value
1 17 blue
1 17 blue
Если эта триада проиндексирована, вам не понадобится индекс (entityid) или составной индекс (entityid, propertyid) в таблице PropertyValues.
* * Тысяча двадцать-одина [/ EDIT] * * тысяча двадцать-дв
Затем я бы создал временную таблицу для хранения соответствующих идентификаторов сущностей.
Затем я итерировал бы свой курсор выше, чтобы захватить идентификатор свойства, пары значений и значений данного объекта, по одной паре за раз, и выдавать оператор выбора с каждой итерацией:
insert into temp
select entityid from PropertyValues
where propertyid = mycursor.propertyid and propertyvalue = mycursor.propertyvalue
В конце цикла у вас есть непонятный набор идентификаторов сущностей в вашей временной таблице для всех сущностей, которые имеют хотя бы одно из общих свойств с данным объектом . Но те, которые вам нужны, должны иметь общие свойства all .
Поскольку вы знаете, сколько свойств имеет данный объект, вы можете сделать следующее, чтобы выбрать только те объекты, которые имеют все общие свойства с данным объектом:
select entityid from temp
group by entityid having count(entityid) = {the number of properties in the given object}
ДОПОЛНЕНИЕ:
После того, как первая пара свойство-значение данного объекта используется для выбора всех потенциальных совпадений, ваша временная таблица не пропустит ни одного возможного совпадения; скорее, он будет содержать сущности, которые не являются идеальными совпадениями, которые должны быть каким-то образом отброшены, либо проигнорированы (вашей группой с помощью предложения ...), либо явно удалены из временной таблицы.
Кроме того, после первой итерации цикла вы можете исследовать возможность того, что внутреннее соединение между временной таблицей и таблицей PropertyValues может обеспечить некоторое повышение производительности:
select entityid from propertvalues
>> inner join temp on temp.entityid = propertyvalues.entityid <<
where propertyid = mycursor.propertyid and propertyvalue = mycursor.propertyvalue
И вы также можете попробовать удалить entityids из temp после первой итерации:
delete from temp
where not exists
(
select entityid from propertyvalues
inner join temp on temp.entityid = propertyvalues.entityid
where propertyid = mycursor.propertyid and propertyvalue = mycursor.propertyvalue
)
В качестве альтернативы можно было бы оптимизировать этот циклический подход, если бы вы сохранили некоторые метаданные о частоте свойства. Оптимально, когда вы ищете совпадения для данного объекта, вы должны начать с наименее часто встречающейся пары свойство-значение . Вы можете упорядочить пары свойств-значений данного объекта по возрастанию частоты, чтобы в вашем цикле вы сначала искали самую редкую. Это уменьшило бы набор потенциальных совпадений до минимально возможного размера на первой итерации цикла.
Конечно, если бы temp был пустым в любое время после того, как первая пара свойства-значения данного объекта использовалась для поиска совпадений, вы бы знали, что для вашего данного объекта нет совпадений, потому что вы нашли свойство-значение что никакая другая сущность не обладает, и вы можете выйти из цикла и вернуть нулевой набор.