За последние 24 часа нас посетили 17495 программистов и 1722 робота. Сейчас ищут 1542 программиста ...

Как работает update, если значения столбцов совпадают с записываемым значение?

Тема в разделе "MySQL", создана пользователем Вероломство, 26 мар 2021.

  1. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    Вопрос возник на почве того, что я пилил AR с уклоном на то, чтобы хранить первоначальные значения по select и потом при update сверять их с текущим состоянием объекта, выбирать только те, которые изменились и выполнять запрос ТОЛЬКО с изменёнными столбцами.

    Теперь вводная:

    Один человек пояснил мне, что я занимался ерундой: не нужно делать никаких сравнений и выборок отличий, а просто делать update всей записи (всех столбцов), потому что мускул ИГНОРИРУЕТ столбцы, в которых не изменилось значение.

    Теперь мой вопрос-рассуждение :)

    1. Как наука смотрит на то, что при таком предложенном варианте производится ХОЛОСТОЙ запрос к БД даже, если не было изменений (у меня такого апдейта не происходит: есть кое-где метод getAfter() который делает save и возвращает данные в вид, этот метод работает всегда, у меня если нет изменений, то save не сделает update, так как нет массива изменённых значений, запроса не будет)

    2. Как наука смотрит на то, что при таком предложенном варианте в строке запроса будет присутствовать апдейт айдишника (мы ведь типа все ведь столбцы берём :))

    то есть получится такой вот цирк - update user set id = ?, login = ? where id = ?

    3. Ну и самый главный вопрос: Если, как говорит мой товарищ, мускул при апдейте игнорирует столбцы, в которых значения не изменялись, то как он это делает? Просто проходит мимо или перезаписывает их, то есть ПРОИСХОДИТ ЛИ физическое действие с носителями (hdd, ssd)?

    Прокомментируйте, пожалуйста :)
     
  2. Drunkenmunky

    Drunkenmunky Активный пользователь

    С нами с:
    12 авг 2020
    Сообщения:
    1.487
    Симпатии:
    281
    Это легко проверить.
    Таблица лежит на диске в виде файла.
    Посчитать хэш, сделать запрос, и снова посчитать.
     
  3. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    таблица: a = 1, b = 2

    запрос: update ... set a = 1, b = 3

    столбец b изменился, тут всё понятно

    как мускул проигнорировал столбец a? перезаписал его или проверил, что в апдейте такое же значение и ФИЗИЧЕСКИ ничего не делал на носителе?
     
  4. Drunkenmunky

    Drunkenmunky Активный пользователь

    С нами с:
    12 авг 2020
    Сообщения:
    1.487
    Симпатии:
    281
    Это не текстовый файл, где если что-то заменить на то же самое ничего не изменится.
    Данные будут записаны в конец, если будут.
    Там где это знать важно заводят столбец с значением по умолчанию CURRENT_TIMESTAMP
     
  5. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.858
    Симпатии:
    748
    Адрес:
    Татарстан
    Вот а тебе не фиолетово? Просто запомни, что он действует именно так. И всякие мегавелосипедыи вокруг этого строить не нужно
     
    Вероломство нравится это.
  6. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    Перезаписывает или проходит мимо, нужно вот знать это, чтобы не тратить время на сомнения :)
     
  7. Drunkenmunky

    Drunkenmunky Активный пользователь

    С нами с:
    12 авг 2020
    Сообщения:
    1.487
    Симпатии:
    281
    Да не, нехай потыкает. Самому интересно стало.
     
  8. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.858
    Симпатии:
    748
    Адрес:
    Татарстан
    Сомнения в чем?
     
  9. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    и как ты проверишь CURRENT_TIMESTAMP ??? :)

    CURRENT_TIMESTAMP один раз пишется, а если у тебя CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, то метка разная и естественно произойдёт физическая запись на диск, ты не уловил наверное суть вопроса
    --- Добавлено ---
    происходит ли физическое воздействие на носитель, если я в столбец со значением 1 пишу значение 1, как мускул игнорирует такой столбец?
     
  10. Drunkenmunky

    Drunkenmunky Активный пользователь

    С нами с:
    12 авг 2020
    Сообщения:
    1.487
    Симпатии:
    281
    Уловил.
    Примечание наверное немного(слегка) не в тему.
     
  11. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    Если бы перезаписывал, то это было бы трудно назвать «ерундой» ;)

    На самом деле по-любому не ерунда. Далеко не везде это работает так, как в мускуле. Плюс, если ты по-любому делаешь предвыборку, можно экономить обратный траф к серверу БД. Куча нашего софта работает подобным образом. И никто не заикается, что это «ерунда» ;)
    --- Добавлено ---
    В частности так отсекаются полностью холостые update'ы, когда ты вообще не отвлекаешь сервер БД впустую.
     
    don.bidon нравится это.
  12. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    ничего не понял

    если я сделал выборку, получил column = 1, ничего ему не менял и сделал update ... set column = 1, то что мускул сделает с column?
     
  13. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    В стартовом посте ты вроде не сомневался в словах чела по поводу объяснения, почему «ерунда» ;) Другие посты не читал, сорри.
    --- Добавлено ---
    Чел прав в том, что мускул делает примерно так же, как это делал ты. Но не совсем прав в том, что раз так, то самому это делать не нужно.
     
    Вероломство нравится это.
  14. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    В стартовом посте я привёл 3 пункта сомнений, по поводу того, что я НЕ СОМНЕВАЛСЯ в чьих-то словах, там ничего я не писал.

    Это МНЕ человек поясняет, что искать изменения в объекте перед сохранением - это ерунда.

    Я считаю, что нужно сохранять только изменённые значения и если предварительно происходить холостой апдейт, то ВООБЩЕ ЕГО НЕ ПРОИЗАОДИТЬ, не делать запрос, не ставить его в очередь... и т.д.

    И считать так буду до тех пор, пока мне не скажут, что мускул не делает ПЕРЕЗАПИСЬ, если он ТУПО ПЕРЕЗАПИСЫВАЕТ неизменённые столбцы своими же значениями, то мне и нахер не упёрлось перепиливать AR свою :)
     
  15. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    См. приписку к моему пред. посту.

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

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    @miketomlin да-да, прочитал приписку: короче как понимаю ТЕБЯ Я :)

    мне нужно сделать так: если нет изменений и где-то лежит холостой апдейт, то подвергнуть его проверке и не производить его

    а если есть изменения, то не возиться с выборкой именно изменённых столбцов, но апдейтить весь объект

    ну вроде догнал, спс :)
    --- Добавлено ---
    @miketomlin просто у меня сделано так

    PHP:
    1. <?php
    2.  
    3.  
    4. namespace core\base;
    5.  
    6.  
    7. use core\Db;
    8.  
    9. abstract class Model
    10. {
    11.     public $id;
    12.     public $original_properties = [];
    13.    
    14.     private static $table_names = [];
    15.  
    16.     public function __construct()
    17.     {
    18.         $properties = (array)$this;
    19.  
    20.         unset($properties['original_properties']);
    21.  
    22.         $this->original_properties = $properties;
    23.     }
    24.  
    25.     public static function count()
    26.     {
    27.         return Db::pdo('select count(*) from ' . self::table())->fetchColumn();
    28.     }
    29.  
    30.     private static function table()
    31.     {
    32.         if (!isset(self::$table_names[static::class])) {
    33.             $class_name = substr(strrchr(static::class, '\\'), 1);
    34.             $table_name = strtolower(preg_replace('~(?<!^)[A-Z]~', '_$0', $class_name));
    35.  
    36.             self::$table_names[static::class] = "`{$table_name}`";
    37.         }
    38.  
    39.         return self::$table_names[static::class];
    40.     }
    41.  
    42.     public static function countBy($params, $values = [])
    43.     {
    44.         return Db::pdo('select count(*) from ' . self::table() . ' where ' . $params, $values)->fetchColumn();
    45.     }
    46.  
    47.     /** @return static */
    48.     public static function findOne($id)
    49.     {
    50.         return current(Db::pdo('select * from ' . self::table() . ' where `id` = ?', [$id], static::class));
    51.     }
    52.  
    53.     /** @return static */
    54.     public static function findOneBy($params, $values = [])
    55.     {
    56.         return current(Db::pdo('select * from ' . self::table() . ' where ' . $params . ' limit 1', $values, static::class));
    57.     }
    58.  
    59.     public static function findAll()
    60.     {
    61.         return Db::pdo('select * from ' . self::table(), [], static::class);
    62.     }
    63.  
    64.     public static function findAllBy($params, $values = [])
    65.     {
    66.         return Db::pdo('select * from ' . self::table() . ' where ' . $params, $values, static::class);
    67.     }
    68.  
    69.     public function save()
    70.     {
    71.         $current_properties = (array)$this;
    72.  
    73.         unset($current_properties['original_properties']);
    74.  
    75.         $properties_diff_array = array_diff_assoc($current_properties, $this->original_properties);
    76.  
    77.         if ($properties_diff_array) {
    78.  
    79.             foreach ($properties_diff_array as $name => $value) {
    80.                 $params[] = "`{$name}` = ?";
    81.                 $values[] = $value;
    82.                 $this->original_properties[$name] = $value;
    83.             }
    84.  
    85.             $params = implode(', ', $params);
    86.  
    87.             if ($this->id) {
    88.                 $values[] = $this->id;
    89.  
    90.                 Db::pdo('update ' . self::table() . ' set ' . $params . ' where `id` = ?', $values);
    91.             } else {
    92.                 Db::pdo('insert into ' . self::table() . ' set ' . $params, $values);
    93.  
    94.                 $this->id = $this->original_properties['id'] = Db::getInstance()->lastInsertId();
    95.             }
    96.         }
    97.     }
    98.  
    99.     public function delete()
    100.     {
    101.         Db::pdo('delete from ' . self::table() . ' where `id` = ?', [$this->id]);
    102.  
    103.         unset($this->id, $this->original_properties['id']);
    104.     }
    105. }
     
  17. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    «ничего не понял» :) Оставь, как было.
    --- Добавлено ---
    Хотя тут важно, в какой момент ты делаешь предвыборку из БД. Если внутри save, то все норм.
    --- Добавлено ---
    А если ты сделал ее в рамках др. действия N часов/минут/секунд назад, то не норм.
     
  18. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    @miketomlin просто у меня сделано та
    PHP:
    1. $user = User::findOne(1);
    2. $user->save(); // моя AR не сделает update, вообще ничего не сделает:)
    3.  
    4. $user->login = 'Test';
    5. $user->save(); // моя AR сделает update ТОЛЬКО столбца `login`
    вот так работает у меня

    у меня в таблицах есть по 30 свойств, представляешь себе какая строка запроса будет если я не буду формировать запрос только по изменённым, ради одного столбца мне крутить в массив параметров и значений всё-равно все свойства придётся, а так я только изменения беру
    --- Добавлено ---
    @miketomlin а вообще СУТЬ вопроса: что делает мускул с неизменёнными столбцами запроса? ПЕРЕЗАПИСЫВАЕТ или ПЕРЕХОДИТ К СЛЕДУЮЩЕМУ

    физически что мускул делает с ДИСКАМИ НА СЕРВАКЕ ЁМАЁ сколько можно повторять :)
     
  19. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    Тебе на этот вопрос уже ответил какой-то чел. Я подтвердил. Это вроде в доках в статье по UPDATE'у написано. Посмотри.
     
  20. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    я если бы нашёл, то не спрашивал бы КАЖДЫЙ ГОД НА РАЗНЫХ форумах одно и то же БЕЗ ОТВЕТА

    не знаешь так и скажи :)
     
  21. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    Я тебе сказал, что чел правильно описал поведение мускула (НЕ перезаписывает дубли), но сделал неправильный вывод из этого.
     
    Вероломство нравится это.
  22. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    вот так и надо было написать в #2 НЕ ПЕРЕЗАПИСЫВАЕТ :)

    и всё
     
  23. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.839
    Симпатии:
    651
    Drunkenmunky пока что не пишет под мою диктовку :)

    А если когда-нибудь и начнет, то там все равно будет написано что-то вроде
    :D

     
  24. Drunkenmunky

    Drunkenmunky Активный пользователь

    С нами с:
    12 авг 2020
    Сообщения:
    1.487
    Симпатии:
    281
    Я ж говорю - это легко проверить.
    Хотя, слегка рассудив промеж себя, то чтобы исключить возможноневерные выводы, слегка усложняем проверку.
    Считаем хэш файла таблицы, обновляем некую запись, изменяя в ней значение, и снова считаем хэш.
    Сверяем. Изменился.
    Снова обновляем ту же строку возвращая первоначальное значение.
    Сверяем - если хэш вернулся в первоначальное же значение, то прекращаем опыт, ибо изначальное предположение неверно.
    Если же хэш новый, то снова делаем тот же запрос и снова считаем хэш.
    Если обновился, то обновление записи происходит, если нет, то нет.
     
  25. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    626
    Симпатии:
    24
    пост 3: содержимое одного столбца изменилось, хеш изменился, содержимое другого столбца не изменялось, вывод: воздействие на носитель произошло при том, что содержимое другого столбца не изменялось - вот результат твоего способа проверки, хешь же разный )))