mysql — сборщик мусора sql против очистки запросов в переполнении стека

Итак, я сделал PHP-скрипт, который производит следующий запрос SQL:

SELECT * FROM icecream WHERE
flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa')
OR flavor = 'marzipan' AND color = 'purple' AND (quality = 'aaa')
OR flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa')

Последний и первый бит запроса идентичны.

Это выглядит неправильно для меня, и, очевидно, я бы предпочел выполнить запрос как

SELECT * FROM icecream WHERE
flavor = 'vanilla' AND color = 'purple' AND (quality = 'aaa')
OR flavor = 'marzipan' AND color = 'purple' AND (quality = 'aaa')

опуская последний ряд.

Который выглядит хорошо в этом примере, но давайте скажем, что
1. Вместо них может быть 23 части «ИЛИ аромат …»
2. 100 разных вкусов
3. 50 разных цветов
4. 20 различных рейтингов качества.

Внезапно становится намного сложнее создать красивый SQL-запрос без дублирующих запросов на одни и те же данные.

Текущий SQL-запрос работает. Но должен ли я очистить запрос, чтобы устранить дублирование, или я должен оставить его движку SQL, чтобы он сделал это для меня?

Я имею в виду, я могу сделать это … но стоит ли это того? С одной стороны, я хочу передавать чистые SQL-запросы, но с другой стороны кажется, что именно такие вещи и предназначены для движка SQL.

Какие-либо предложения?

0

Решение

Вы можете ответить на свой вопрос, прочитав план запроса, созданный оптимизатором MySQL, используя EXPLAIN [EXTENDED] SELECT ..., Если планы совпадают, то сервер не только считает ваши запросы логически эквивалентными, но и сократил их до одного и того же запроса.

https://dev.mysql.com/doc/refman/5.7/en/explain.html

Вы должны предпочесть, чтобы сгенерированные запросы были логически оптимальными, не делая вещей, которые могли бы уменьшить опции, доступные оптимизатору (делая нежелательные вещи, такие как использование имен столбцов в качестве аргументов функции в WHEREи быть отлаживаемым. Там нет необходимости в хитрости.

(a = 1 AND b = 1 AND c = 5) OR
(a = 1 AND b = 1 AND c = 27)

…полностью эквивалентно …

(a = 1 AND b = 1) AND (c = 5 OR c = 27)

….или же…

(a = 1 AND b = 1 AND c IN (5,27))

…и оптимизатор легко поймет эти условия независимо от того, как они выражены в запросе. Полученный план должен быть идентичен, поэтому нет необходимости отдавать предпочтение одному из других при создании динамических запросов. (Старые версии MySQL не обязательно обрабатывали последнюю, а также первые две, но сейчас это не должно быть проблемой.)

Важно отметить, что WHERE конечно, будучи логическим выражением, имеет детерминированный приоритет оценки с логической точки зрения, но это не то же самое, что упорядочение оценки по каждой строке … теоретически не существует порядка, в котором выполняется оценка условий конечного выражения упорядочены — но оптимизатор может свободно на самом деле оценивать условия в любом порядке, который кажется правильным и оптимальным, независимо от того, как они выражены.

Основываясь на поиске по индексу, здесь можно выбрать поиск всех b = 1 строки, а затем найти c = 5 OR c = 27 в этом наборе, и, наконец, просмотрите полученные строки для a = 1 состояние. Это может быть в случае, если у вас был один индекс по столбцам (b,c), Там нет сокращения в процедурном смысле — WHERE a = 1 AND b = 1 логически идентичен WHERE b = 1 AND a = 1,

Обратите внимание, что в примерах запросов следует использовать больше скобок, чтобы группировка приоритета AND / OR была однозначной. Конечно, сервер все сделает правильно, но глазные яблоки легче обмануть, а круглые скобки, которые делают вещи однозначными для глазных яблок, не окажут плохую услугу оптимизатору MySQL, который, кажется, любит их.

2

Другие решения

Хорошо, вопросы, которые я вижу:

1) Будет ли движок SQL удалять дубликаты?

это то, что движок SQL действительно предназначен для

2) Как я могу передать чистые запросы без чрезмерных усилий?

Я хочу передать чистые запросы SQL


SQL является декларативным языком.

декларативный язык означает, что вы говорите ему, что делать, он определяет, как это сделать.

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


Кажется, что ваш php-скрипт фокусируется на низком уровне абстракции.

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

Недостатком этого метода является изменение или настройка объекта результата. Преобразователь не знает, что произошло на предыдущем этапе, и не может легко обнаружить и удалить повторяющиеся строки. Вам нужно иметь какой-то объект, который может помочь взять некоторые правила и создать из них SQL-запрос. (Одним из таких инструментов является Zend Db).


Наконец, я просто хотел бы отметить, что запрос, который вы пытаетесь сделать, кажется излишне сложным.

23 части «ИЛИ аромат …»

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

1

По вопросам рекламы [email protected]