Как эффективно выбирать строки NON-NULL, NON-EMPTY на основе нескольких столбцов? - PullRequest
0 голосов
/ 05 августа 2020

Приведенный ниже запрос работает, однако мне интересно, есть ли способ его оптимизировать? В его нынешнем виде он будет выполнять несколько сканирований таблиц для каждого оператора OR?

Причина, по которой я защищаюсь в запросе, заключается в том, что если кто-то передаст NULL или пустую строку в # {phone} или # {email } он удалит много данных в дальнейшем в процессе. Поэтому крайне важно выбирать ТОЛЬКО строго совпадающие значения для каждого оператора OR.

SELECT ID 
FROM...

    WHERE (phone != '' AND phone IS NOT NULL AND phone = #{phone})

    OR (phone2 != '' AND phone2 IS NOT NULL AND phone2 = #{phone})

    OR (phone3 != '' AND phone3 IS NOT NULL AND phone3 = #{phone})

    OR (email != '' AND email IS NOT NULL AND email = #{email})

1 Ответ

1 голос
/ 05 августа 2020

Я думаю, что параметр phone следует дезинфицировать на уровне приложения, а не в базе данных.

Однако, если он настолько важен, как вы упомянули, иногда удобно принять некоторые меры безопасности, например те, которые вы используете. В этом случае запрос выглядит хорошо.

С точки зрения производительности запрос может выиграть от индексов:

create index ix1 on t (phone);

create index ix2 on t (phone2);

create index ix3 on t (phone3);

create index ix4 on t (email);

Теперь, в зависимости от оптимизации и гистограммы данных, Engine может отказаться от использования индексов. В этом случае вы можете продвигать использование указанных выше индексов, перефразируя свой запрос, используя UNION вместо OR (старый трюк). Например:

SELECT ID 
WHERE (phone != '' AND phone IS NOT NULL AND phone = #{phone})
FROM...
UNION
SELECT ID 
WHERE (phone2 != '' AND phone2 IS NOT NULL AND phone2 = #{phone})
FROM...
UNION
SELECT ID 
WHERE (phone3 != '' AND phone3 IS NOT NULL AND phone3 = #{phone})
FROM...
UNION
SELECT ID 
WHERE (email != '' AND email IS NOT NULL AND email = #{email})

Механизму намного проще использовать индекс, когда в предикате нет OR. Однако этот трюк окупается позже при выполнении UNION s. Если количество выбранных строк невелико, эта стоимость должна быть минимальной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...