Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет Леонид Каганов ([info]lleokaganov)
@ 2022-12-20 04:24:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Entry tags:как не надо программировать

Для программистов. Маленькие радости Mariadb MySQL
взято отсюда: https://lleo.me/dnevnik/2022/12/20

До последних версий Mariadb при попытке записать в таблицу уже имеющиеся там данные возвращала спокойную ошибку. Это ошибку обрабатывал скрипт PHP, и все было нормально.

Но последние версии Mariadb (в частности 15.1 Distrib 10.6.11-MariaDB, for debian-linux-gnu x86_64) в таком случае стали выдавать настолько фатальную ошибку, которую уже не обработать, потому что на ней рушится сам вызвавший ее скрипт PHP. Потому что блять ну нельзя же пытаться записать данные, когда в таблице они уже есть! Шок! Паника! Вызывайте наряд Гестапо! Вот если, скажем, в поле varchar(11) попытаться записать телефонный номер в 12 символов — а вот это блять у нас можно, это вовсе никакая не ошибка, а дело житейское. Мы просто тихо обрежем последнюю цифру телефона и так запишем. Звоните теперь, ваш звонок очень важен для нас.

Короче, я бегло погуглил и не нашел, что случилось, какой ебаный гений в очередной раз изобрел по дефолту всем бывшим пользователям MySQL очередной катаклизм, и как это лечить. То есть — в какую внутреннюю базу настроек надо чем залогиниться или какой ini-файл поправить, указав какую-нибудь свежевыебаную опцию duble_fatal_error_please_no_no_please=false.

Я решил вопрос тупо, но эффективно: добавил запрос-проверку перед записью. Но старшие товарищи мне объяснили, что так поступать дорого, потому что в MySQL есть специально для этого опция INSERT IGNORE. Ок. Я вписал эту опцию, и вроде все заработало... Но со временем я стал замечать, что индекс автоинкремента в таблице неуёмно растет. Схуяль? И тут выяснилось, что INSERT IGNORE индекс по-любому увеличит — вне зависимости, создала она новую запись или нет. С какой целью она это делает, спросите вы? Да хуй знает. Это же Mariadb.

Пример? Созданную таблицу с auto_increment и не позволяющим дублирование полем val полностью очищаем перед сеансом. Записываем val=1. Затем еще десяток раз пытаемся снова (и безуспешно) записать val=1 при помощи INSERT IGNORE. Потом записываем val=2.

msq('CREATE TABLE IF NOT EXISTS test (
  id tinyint(10) NOT NULL auto_increment,
  val int(10) NOT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY (val)
) ENGINE=InnoDB AUTO_INCREMENT=1;');

msq('TRUNCATE test');

function insert($i) { msq('INSERT IGNORE INTO test SET val='.$i); return msq_id(); }

echo '\n insert val=1, id='.insert(1);

for($i=2;$i<=10;$i++) echo "\n  try #".$i." to insert val=1, id=".insert(1);
// echo "\n"; for($i=2;$i<=126;$i++) { echo $i." "; insert(1); }

echo "\n insert val=2, id=".insert(2);

Результат:

insert val=1, id=1
  try #2 to insert val=1, id=0
  try #3 to insert val=1, id=0
  try #4 to insert val=1, id=0
  try #5 to insert val=1, id=0
  try #6 to insert val=1, id=0
  try #7 to insert val=1, id=0
  try #8 to insert val=1, id=0
  try #9 to insert val=1, id=0
  try #10 to insert val=1, id=0
insert val=2, id=11

Сколько было попыток повторно записать val=1 — на сколько теперь увеличился счетчик id. Ну а если безуспешных попыток будет не десяток, а... ну, скажем, 125 (как вы догадались, я не случайно указал в примере tinyint, да еще без unsigned) — то всё, пиздец, вы ничего уже никогда в эту таблицу больше не запишете. Размерность счетчика исчерпалась на бесплодные попытки:

insert val=1, id=1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
insert val=2, id=127
insert val=3, id=0
insert val=4, id=0

Если не это пиздец инженерной мысли, то что тогда?

Сейчас, разумеется, в комменты набегут пожилые члены Cекты Свидетели Безгрешной Девы МарииДБ и расскажут нам, что это не бага, а фича. Что счетчик это вовсе не счетчик ячеек, а счетчик обращений. И что пики точёные расставлены на стуле для вашего удобства. Просто надо уметь ими пользоваться как мы, когда каждый день садимся на этот стул работать.