Случай и если производительность в запросе MySQL

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

IF progress = 0
    IF start<now() AND end>now() THEN "delay"
    IF start<now() AND end<now() THEN "overdue"
IF progress BETWEEN 0 AND 1
    IF start<now() THEN "advanced"
    IF end<now() THEN "overdue"
    IF end>now() AND end*progress>=now() THEN "in progress"
    IF end>now() AND end*progress<now() THEN "delayed"
IF progress=1 THEN "completed"

Я смотрю, как установить этот набор условий с точки зрения производительности. Должен ли я изменить внешний IF (тот, что касается поля прогресса) на CASE?

BETWEEN является инклюзивным, поэтому условия частично совпадают. CASE можно использовать только при взаимоисключающих условиях. Поэтому, если вы измените это на CASE, это не будет эквивалентно.
Barmar 05.07.2024 18:33

Если производительность является основным фактором, я бы рекомендовал определить сгенерированный столбец как столбец STORED. Тогда производительность выражения влияет только на вставку/обновление строки, а не на чтение вычисленного значения. Виртуальный сгенерированный столбец оценивает выражение при каждом чтении. Сохраненный столбец оценивает выражение только один раз, когда вы вставляете/обновляете строку.

Bill Karwin 05.07.2024 18:37

Если вы хотите проверить относительную производительность выражений, попробуйте использовать функцию MySQL BENCHMARK().

Bill Karwin 05.07.2024 18:39

@BillKarwin Разве выбор не зависит от того, чаще ли вы читаете или пишете соответствующие колонки?

Barmar 05.07.2024 18:49

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

Lelio Faieta 05.07.2024 18:57

В любом случае вы не можете использовать NOW() в выражении сгенерированного столбца. Возможно, вам придется использовать представление.

Bill Karwin 05.07.2024 19:13

@Barmar, Да, вы правы, но число операций чтения обычно значительно превышает число операций записи.

Bill Karwin 05.07.2024 19:14

Предполагая, что вы решите проблему перекрытия, о которой я упоминал выше, обычно следует отдавать предпочтение CASE, поскольку он прекращает проверку условий, как только одно из условий выполнено успешно. Ваш код будет проверять наличие progress=1, даже если он уже нашел это progress=0.

Barmar 05.07.2024 19:20

Кроме того, если вы остаетесь с IF, используйте конструкцию IF..ELSEIF..ELSE, если только не будет выполнено несколько условий.

ticktalk 05.07.2024 21:48

@BillKarwin Сейчас я использую упрощенную версию этих условий, и теперь она работает безупречно. Почему ты говоришь, что я не могу?

Lelio Faieta 05.07.2024 22:06

Это в триггере или вы определяете его как сгенерированный столбец? Какой результат SELECT VERSION(); ?

Bill Karwin 05.07.2024 22:17

@BillKarwin Я использую это как часть обычного выбора, а не триггера. И я использую MySQL версии 8.3.0.

Lelio Faieta 06.07.2024 16:00

Хорошо, вы можете использовать NOW() в выражении. Я допустил ошибку, полагая, что вы определяете выражение как сгенерированный столбец таблицы. Существуют ограничения на то, какие функции можно использовать в определениях созданных столбцов.

Bill Karwin 06.07.2024 18:02

Синтаксис, который вы показываете в своем вопросе, не является допустимым синтаксисом для выражения MySQL IF(). Возможно, если вы покажете пример рабочего запроса.

Bill Karwin 06.07.2024 18:19
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
14
54
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Короткий ответ: разница в производительности между IF и CASE, вероятно, незначительна.

Длинный ответ: Ну, ваш код не будет работать в его нынешнем виде, но позвольте мне угадать, что вы намеревались сделать:

IF start<now() AND end>now() THEN "delay"
IF start<now() AND end<now() THEN "overdue"

Предположим, что start обязательно меньше end, измените на

IF (start<now()) THEN
    IF (end>now()) THEN "delay" ELSE IF (end<now()) THEN "overdue"

или

IF (start<now()) THEN
    CASE WHEN end>now() THEN "delay"
         WHEN end<now() THEN "overdue"
    END

end*progress слишком запутанно для слов. Запишите IF или CASE, а затем упростите.

Ответ принят как подходящий

Я смотрю, как установить этот набор условий с точки зрения производительности. Должен ли я изменить внешний IF (тот, что касается поля прогресса) на CASE?

Это не имеет значения. Любая разница будет тривиальной. MySQL может даже реализовать их точно так же.

Поскольку это часть предложения select, оно влияет только на уже выбранные строки. Процесс чтения, фильтрации и сортировки строк намного дороже. Гораздо важнее сосредоточить усилия по оптимизации на этих частях вашего запроса: where, order by, join, group by, ваших индексах и так далее.


Примечание. end — зарезервированное слово SQL; неясно, ссылаетесь ли вы на столбец или завершаете блок, и это может привести к трудно отлаживаемым ошибкам. Рассмотрите возможность использования соглашений *_at и *_on для отметок времени и дат соответственно. start_at и end_at для меток времени, start_on и end_on для дат.

Другие вопросы по теме