Подтвердить что ты не робот

Насколько плохо мой запрос?

Ok Мне нужно создать запрос, основанный на некотором пользовательском входе для фильтрации результатов.

В основном запрос выглядит примерно так:

SELECT * FROM my_table ORDER BY ordering_fld;

Есть четыре текстовых поля, в которых пользователи могут фильтровать данные, что означает, что мне пришлось бы динамически строить в нем предложение "WHERE" для первого используемого фильтра, а затем предложения "И" для каждого последующего фильтра.

Поскольку я слишком ленив, чтобы сделать это, я только что сделал каждый фильтр предложением "И" и по умолчанию поставил предложение WHERE 1 в запросе.

Итак, теперь у меня есть:

SELECT * FROM my_table WHERE 1 {AND filters} ORDER BY ordering_fld;

Итак, мой вопрос: сделал ли я что-то, что отрицательно повлияет на производительность моего запроса или что-то еще не сработает, я должен быть удаленно обеспокоен?

4b9b3361

Ответ 1

MySQL будет оптимизировать ваш 1.

Я просто запустил этот запрос в своей тестовой базе данных:

EXPLAIN EXTENDED
SELECT  *
FROM    t_source
WHERE   1 AND id < 100

и он дал мне следующий description:

select `test`.`t_source`.`id` AS `id`,`test`.`t_source`.`value` AS `value`,`test`.`t_source`.`val` AS `val`,`test`.`t_source`.`nid` AS `nid` from `test`.`t_source` where (`test`.`t_source`.`id` < 100)

Как вы можете видеть, нет 1 вообще.

В документации WHERE оптимизация предложения в MySQL упоминается следующее:

  • Постоянное складывание:

    (a<b AND b=c) AND a=5
    -> b>5 AND b=c AND a=5
    
  • Удаление константного состояния (необходимо из-за постоянного складывания):

    (B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
    -> B=5 OR B=6
    

Примечание 5 = 5 и 5 = 6 части в приведенном выше примере.

Ответ 2

Вы можете ОБЪЯСНИТЬ ваш запрос:
http://dev.mysql.com/doc/refman/5.0/en/explain.html

и посмотрим, делает ли он что-то по-другому, что я сомневаюсь. Я бы использовал 1 = 1, так что это более понятно.

Возможно, вы захотите добавить LIMIT 1000 или что-то еще, когда параметры не используются и таблица становится большой, действительно ли вы хотите вернуть все?

Ответ 3

WHERE 1 - это постоянное детерминированное выражение, которое будет "оптимизировано" любым достойным механизмом БД.

Ответ 4

Если на вашем выбранном языке есть хороший способ избежать создания SQL самостоятельно, используйте это вместо этого. Мне нравятся Python и Django, а Django ORM позволяет легко фильтровать результаты на основе пользовательского ввода.

Если вы привержены построению SQL самостоятельно, не забудьте очистить входы пользователя от SQL-инъекции и попытайтесь инкапсулировать SQL-построение в отдельный модуль из вашей логики фильтра.

Кроме того, производительность запросов не должна быть вашей проблемой, пока это не станет проблемой, которая, вероятно, не будет, пока у вас не будет тысяч или миллионов строк. И когда пришло время оптимизировать, добавление нескольких индексов для столбцов, используемых для WHERE и JOIN, идет долгий путь.

Ответ 5

Чтобы повысить производительность, используйте индексы столбцов в полях, прослушиваемых в "ГДЕ"

Ответ 6

Отказ от стандартных инъекций SQL здесь...

Одна вещь, которую вы могли бы сделать, чтобы избежать инъекции SQL, поскольку вы знаете, что только четыре параметра используют хранимую процедуру, в которой вы передаете значения для полей или NULL. Я не уверен в синтаксисе хранимых профайлов mySQL, но запрос будет сжиматься до

SELECT *
  FROM my_table
 WHERE Field1 = ISNULL(@Field1, Field1)
   AND Field2 = ISNULL(@Field2, Field2)
   ...
 ORDRE BY ordering_fld

Ответ 7

Мы делали что-то похожее не так давно, и есть несколько вещей, которые мы наблюдали:

  • Настройка индексов на столбцах, которые мы (возможно) фильтровали, улучшали производительность
  • Часть WHERE 1 может быть полностью исключена, если фильтры не используются. (не уверен, относится ли это к вашему делу) Не имеет значения, но "чувствует" право.
  • Не следует забывать SQL-инъекцию

Кроме того, если у вас есть только 4 фильтра, вы можете создать хранимую процедуру и передать нулевые значения и проверить их. (так же, как и n8wrl)

Ответ 8

Это сработает - некоторые соображения:

О динамически построенных SQL в целом, некоторые базы данных (по крайней мере, Oracle) будут кэшировать планы выполнения запросов, поэтому, если вы будете запускать один и тот же запрос много раз, ему не придется полностью начинать с нуля. Если вы используете динамически построенный SQL, вы каждый раз создаете другой запрос, поэтому в базу данных он будет выглядеть как 100 различных запросов вместо 100 запусков одного и того же запроса.

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

Вам нужны все столбцы? Явное указание их, вероятно, лучше, чем использование * anyways, потому что:

  • Вы можете визуально увидеть, какие столбцы возвращаются.
  • Если вы добавите или удалите столбцы в таблицу позже, они не изменят ваш интерфейс

Ответ 9

Неплохо, я не знал этого фрагмента, чтобы избавиться от вопроса "это первый фильтр 3".

Вам должно быть стыдно за ваш код (^^), он ничего не делает для производительности, поскольку любой движок БД оптимизирует его.

Ответ 10

Единственная причина, по которой я использовал WHERE 1 = 1, для динамического SQL; это взломать, чтобы упростить добавление предложений WHERE, используя AND .... Это не то, что я хотел бы включить в мой SQL в противном случае - он не делает ничего, чтобы повлиять на общий запрос, потому что он всегда оценивается как истинный и не попадает в таблицу (-ы), поэтому нет никаких поисков индексов или табличных сканирований на основе он.

Я не могу говорить о том, как MySQL обрабатывает необязательные критерии, но я знаю, что используя следующее:

WHERE (@param IS NULL OR t.column = @param)

... является типичным способом обработки необязательных параметров. COALESCE и ISNULL не идеальны, потому что запрос все еще использует индексы (или, что хуже, сканирование таблиц) на основе контрольного значения. Представленный мной пример не попадет в таблицу, если не указано значение.

Таким образом, мой опыт работы с Oracle (9i, 10g) показал, что он не обрабатывает [ WHERE (@param IS NULL OR t.column = @param)] очень хорошо. Я увидел огромный прирост производительности за счет преобразования SQL в динамический и использовал переменные CONTEXT, чтобы определить, что добавить. Мое впечатление от SQL Server 2005 заключается в том, что они обрабатываются лучше.

Ответ 11

Я обычно делал что-то вроде этого:

for(int i=0; i<numConditions; i++) {
  sql += (i == 0 ? "WHERE " : "AND ");
  sql += dbFieldNames[i] + " = " + safeVariableValues[i];
}

Делает сгенерированный запрос немного более чистым.

Ответ 12

Одна из альтернатив, которую я иногда использую, заключается в том, чтобы построить предложение where в массиве и затем объединить их:

my @wherefields;
foreach $c (@conditionfields) {
  push @wherefields, "$c = ?",
}

my $sql = "select * from table";
if(@wherefields) { $sql.=" WHERE " . join (" AND ", @wherefields); }

Выше описано в perl, но большинство языков имеют какую-то функцию соединения.