Очень сложная проблема.Похоже, что пользователи будут добавляться с большой скоростью, с купонами с довольно регулярной частотой.
Добавление SQL в таблицу для динамического использования - работоспособно - по крайней мере, вы получите новый план выполнения - НО вашкэш плана может увеличиться.
У меня такое ощущение, что запуск одного купона для всех пользователей, вероятно, будет вашим самым эффективным запросом, потому что это один набор критериев, который будет достаточно избирательным для пользователей в первую очередь и всегоколичество купонов невелико, тогда как запуск всех купонов для одного пользователя является отдельным критерием для каждого купона для этого пользователя.Выполнение всех купонов для всех пользователей может по-прежнему работать хорошо, даже если сначала это будет перекрестное соединение - я думаю, что это будет зависеть.
В любом случае, дело касается всех купонов для всех пользователей (или в любом случае, действительно) будет выглядеть примерно так:
SELECT user.id, coupon.id
FROM user
INNER JOIN coupon
ON (
CASE WHEN <coupon.criteria> THEN <coupon.id> -- code generated from the coupon rules table
CASE WHEN <coupon.criteria> THEN <coupon.id> -- etc.
ELSE NULL
) = coupon.id
Чтобы сгенерировать правила купона, вы можете относительно легко выполнить объединение строк одним движением (и вы можете объединить дизайн отдельных строк правил для купона сИ с дополнительным внутренним шаблоном):
DECLARE @outer_template AS varchar(max) = 'SELECT user.id, coupon.id
FROM user
INNER JOIN coupon
ON (
{template}
ELSE NULL
) = coupon.id
';
DECLARE @template AS varchar(max) = 'CASE WHEN {coupon.rule} THEN {coupon.id}{crlf}';
DECLARE @coupon AS TABLE (id INT, [rule] varchar(max));
INSERT INTO @coupon VALUES
(1, 'user.Age BETWEEN 20 AND 29')
,(2, 'user.Color = ''Yellow''');
DECLARE @sql AS varchar(MAX) = REPLACE(
@outer_template
,'{template}',
REPLACE((
SELECT REPLACE(REPLACE(
@template
,'{coupon.rule}', coupon.[rule])
, '{coupon.id}', coupon.id)
FROM @coupon AS coupon
FOR XML PATH('')
), '{crlf}', CHAR(13) + CHAR(10)));
PRINT @sql;
// EXEC (@sql);
Есть способы сделать это - поиграйте с этим здесь: http://data.stackexchange.com/stackoverflow/q/115098/
Я бы рассмотрел добавление вычисляемых столбцов (возможно, сохранившихся и проиндексированных)помогать.Например, вычисляемый столбец age - non-persisted, вероятно, будет работать лучше, чем скалярная функция.
Я бы посоветовал объединить это с таблицей, в которой указано, действителен ли купон для пользователя и когда он был последний раз подтвержден.
Похоже, возраст может измениться, и пользователь может стать действительным или недействительным.для купона в день рождения.
Когда пользователь входит в систему, вы можете создать фоновое задание для обновления купонов.При последующих входах в систему не будет необходимости обновлять (поскольку вряд ли это изменится до следующего дня или вызывающего события).
Всего несколько идей.
Я бы тожедобавьте, что у вас должен быть способ протестировать купон до его утверждения, чтобы убедиться в отсутствии синтаксических ошибок (поскольку SQL является произвольным или произвольным) - это можно сделать относительно легко - возможно, с помощью тестовой пользовательской таблицы (test_user в качестве пользователя ввместо этого необходимо, чтобы сгенерированный шаблон кода) содержал строки «годен» и «нет», и правило купона указывает на них.Мало того, что EXEC должен работать - возвращаемые строки должны быть ожидаемыми и только ожидаемыми строками для этого купона.