--}}
Новая тема
Вы не можете создавать новые темы.
Т.к. вы неавторизованы на сайте. Пожалуйста назовите себя или зарегистрируйтесь.
Список тем

Mysql INSERT IGNORE auto-increment holes

Серьёзная тема
585
22
С друзьями на NN.RU
В социальных сетях
Поделиться
Qavai
20 февраля в 12:47
Оказывается, интересные вещи есть, я только спустя 16 лет практики наткнулся на этот баг =)

Вот думаю, как обойти это.

Вы как справляетесь с этим?
DimN
21 февраля в 17:04
А почему это баг и зачем с ним справляться?
Qavai
21 февраля в 18:45
это даже не баг, а фича, неприятная, если не знать о ней.

решение простое с виду

"INSERT INTO `table`(#fields#)
SELECT #values# FROM dual WHERE NOT EXISTS(
SELECT NULL FROM `table` WHERE `title`=#values#
DimN
21 февраля в 19:40
Это фича совершенно всех СУБД (ну, возможно, существуют и другие, но я не хочу о них даже слышать), как можно об этом не знать? Любая неудачная попытка вставки всё равно сдвигает автоинкрементный счетчик, это нормально, если мы не хотим иметь геморрой с блокировками в многопользовательских приложениях.

И второй вопрос: зачем бороться с дырами? Они неизбежны при любых извращениях. Например, они появятся при rollback или просто при банальном delete. И даже попытка защититься при помощи not exists не сработает, если не повысить уровень изоляции транзакции со стандартного read committed, потому что иначе между проверкой и вставкой кто-то может влезть, хоть и с очень небольшой вероятностью, конечно.

Нельзя суррогат использовать в бизнес-логике. Если прям требуется какая-то непрерывная нумерация, скажем, документов (хотя обычно достаточно уникальности и иногда возрастания, причем, нередко со сбросом номера в ноль с наступлением нового года), писать честную нумерацию с блокировками и мириться с дополнительными расходами.
Qavai
21 февраля в 23:37
ну при чём тут сразу многопользовательское?

у меня вот просто таблица с тегами.
и я её наполняю.
один юзер. больше никого нет

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

так просто удобнее и симпатишнее, чем если, например, 5000 слов, а последний id будет равен какому-нибудь 35000, а не 5000

и через вот этот запрос это работает.
но, конечно, можно сделать и по другому, сложнее, но зачем?

в моей задаче этого не требуется
DimN
22 февраля в 00:33
Не, ну дело хозяйское, если так уж хочется :о) Но если вставляет один юзер, скорее всего, дублей будет считаные единицы и id будет 5010, например. Хотя, на мой вкус, и 35000 ничем не плохо.

А если в транзакции, кроме вставки в эту таблицу, есть еще какие-то действия, которые вызовут ошибку и приведут к откату транзакции, всё равно получите дырку :о)
Qavai
22 февраля в 13:43
да я тут небольшую задачку реализовал

есть вакансии на хабре https://career.habr.com/vacancies/rss...

это rss

я проверяю каждые 15 минут и заношу их в базу данных
там список 50 шт
там у каждой вакансии есть Требуемые навыки, это теги

// Требуемые навыки: #senior, #Java, #Kotlin, #PostgreSQL, #MySQL, #ApacheKafka, #RabbitMQ, #Kubernetes, #Docker, #SpringBoot.

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

так вот, к теме
около 150 тегов каждые 15 минут заносятся в таблицу
и вот когда через час я увидел список тегов в количестве 900, а id в районе 3000, ну это просто не очень хорошо
и оно будет продолжать увеличиваться, дыр просто очень много. по экспоненте идут.

никаких многопользователей тут нет, транзакций и т.п. нет, всё в один поток
DimN
23 февраля в 10:32
Ну в целом понятно... В общем случае проверка существования записи кошернее, чем вставка с игнором ошибки, и дело даже не в дырках автоинкремента, а в том, что ошибку нужно поймать и обработать, иначе с логикой работы приложения могут быть проблемы.

Вот рассмотрим ваш случай. Я так понял, есть три таблицы: Т1 -- справочник тегов, в который заносятся уникальные значения этих тегов, Т2 -- таблица вакансий, Т3 -- таблица для хранения связи между ID вакансии и ID тегов, которые в этой вакансии упоминаются. Судя по всему, алгоритм примерно такой: сначала вакансия разбирается один раз для сохранения новых тегов в Т1, а потом еще раз пробегаем по всем тегам вакансии, находим их ID в Т1 и заполняем Т3. Двойная работа. Обычно делается так: пробегаем по тегам вакансии и ищем каждый тег в Т1.
1) если находим, то найденный ID тега сохраняем в Т3,
2) если не находим, то вставляем запись в Т1, получаем ID тега не поиском(!), а средствами СУБД, каждая из них умеет возвращать значение последнего вставленного автоинкремента (беглое гугление говорит, что для MySQL это last_inser_id(), может и другие функции есть). Полученный ID также сохраняем в Т3.

И вот в случае игнора ошибки вы лишаетесь возможности использовать средство СУБД и вынуждены два раза искать тег в справочнике: сначала при вставке, потом для сохранения связи.

Но, конечно, для игрушечной задачи всё это не имеет никакого значения :о)
Qavai
23 февраля в 16:12
вероятно, так и сделаю, просто позже.

просто пока не стал делать таблицу связей, поэтому id и не нужен.

обычно в реальном проекте я не пользуюсь ignore, здесь просто так было проще сделать, одним запросом в бд
Qavai
4 марта в 09:21
сделал вывод списка e-ivanov.ru/projects/careerhabrcom-own-filters/live/

это список вакансий, которые не-поднятые, то есть, совершенно новые.

как видно, намного меньше стало мишуры

скоро добавлю фильтры тагов
DimN
9 марта в 09:17
Пэйджинг надо поправить, первая страница выдачи должна иметь номер 1, а не 76 :о)
Qavai
9 марта в 10:49
нет.
первая страница - она и есть первая, там первые записи идут.
а 76 - это самые последние записи

это обратный страничник, моё изобретение

если данные из списка не удаляются (а это на 100% так), то на 60 странице https://e-ivanov.ru/projects/careerha... , например, мы ВСЕГДА будем находить одни и те же записи, те сверху будет всегда "Требуется Full-stack middle-middle+ программист (YII2, VUE) (Кострома)", сколько бы записей не добавилось новых, те, даже когда будет всего 120 или 1200 страниц.

а если делать прямой страничник (который неправилен для временнЫх записей), то на 60 странице после добавления новых записей будет постоянно сдвигаться записи и мы через месяц или год не найдём на 60 странице ту запись, которую там видели.
DimN
9 марта в 12:56
А зачем нам, чтобы какая-то древняя запись всегда лежала на одной и той же странице (тем более что эта страница сохранится только при поиске по тем же критериям)? ИМХО, это странное желание из того же разряда, что и отсутствие дыр в автоинкременте :о) То есть через год я буду помнить, что при поиске вакансии по ключевым словам "MySQL", "PHP", "зарплата от 300 000" что-то интересное было на 60-й странице? Если мне интересна конкретная вакансия, я сохраню прямую ссылку на нее (хоть эта вакансия и протухнет в скором времени).

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

Ну, если так и задумано, то ОК, я ж ТЗ не читал, думал, баг :о)
diper
11 марта в 10:42
Большие компании напрямую с hh не работают, а используют какую-нидь прокладку для автоматизации процесса HR, в том числе для бампа вакансий по расписанию.

Искать вакансии "алмазы"... лучше будь сам алмазом чтоб тебя искали)
Qavai
11 марта в 11:31
не находят.

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



история:



я вот недавно в декабре случайно нашёл пару интересных вакансий на хабркарьере, да и то где-то на 10 странице, долго прокручивал и отсеивал мишуру.



пособеседовался, в одну шаражку взяли, дали 120 на испытательный, потом 140



но я туда не пошёл, потому что они не ответили на 5...10 простых вопросов (про отпуска и т.п.), хрюша сказала "мне тупо лень отвечать"

типа давай работай



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



вот так вот.

поэтому вот и занялся этим проектом, чтобы не тратить время на поиск нужных мне вакансий. на самом сайте уж неудобные фильтры, да и нет rss для них
DimN
11 марта в 12:37
Qavai писал(а)
пособеседовался, в одну шаражку взяли, дали 120 на испытательный, потом 140
...
а потом глянул их вакансии на хх, там мастер рабочий без опыта - 90, с опытом 120. гибкие окна делать.
Ну это понятно, есть куча фирм, где айтишное подразделение -- необходимое зло, не приносящее денег, а только их потребляющее. Соответственно, отношение к таким обслуживающим структурам не самое позитивное. Лучше стремиться работать в фирмах, для которых ИТ -- основная деятельность.

Раньше к таким бизнесам, где ИТ -- обслуга, относились и банки, но сейчас многие из них при помощи ИТ зарабатывают больше, чем при помощи маринок в отделениях и разного рода кредитных менеджеров. Плюс ИТ выделяют в обособленные структуры со своим руководством, имеющим вес в общей иерархии, что способствует повышению статуса айтишников. То есть работа в ИТ-структурах банков стала мало чем отличаться от работы в обычных девелоперских фирмах.
Qavai
11 марта в 22:34
наконец-то доделал фильтры по тегам.

проставил на каждый тег по весу. от -100 до 100 можно ставить
проставил на ненужные мне теги -100, и вот сразу стало 155 вакансий, а всего их 2100
крысота!
пофиксил rss, теперь там всё хорошо
но 155 - это для меня только, когда я авторизован.

остальные продолжают видеть без фильтров. там сейчас 833 шт
но тоже неплохо, остальные 1300 мишура скрыты

пользуйтесь

запрос такой набросал, работает быстро

INNER JOIN (
SELECT i4t.guid, MIN(t.cost) AS min_cost, t.title AS tag_title FROM `habr_career_tags` AS t
INNER JOIN `habr_career_item4tag` AS i4t
ON (
i4t.tag_id = t.id
)
WHERE 1
GROUP BY guid
HAVING min_cost >= 0
) AS pt ON (
pt.guid = p.guid
)

позже может быть сделаю на странице форму с выбором тегов, которые нужно игнорировать
пока есть другой проект
Atom
21 февраля в 20:57
Почему баг-то? )
diper
1 марта в 23:44
а вариант по первой ссылке со stackoverflow чем не вариант?
Qavai
5 марта в 11:08
там полно вариантов
Саламан
8 марта в 00:04
auto-increment id - это техническое поле оно может иметь абсолютно любое значение.
оно нужно только для удобной связи между таблицами.
По сути вы вообще не должны на него полагаться, поскольку auto-increment id могут изменяться в ходе восстановления или копирования данных или прочих админских работ.
Qavai
8 марта в 17:24
уже накопилось 2000 вакансий

вот такая раскладка по умениям (тегам), самым популярным:

e-ivanov.ru/p/2403/8d.png
Новая тема
Вы не можете создавать новые темы.
Т.к. вы неавторизованы на сайте. Пожалуйста назовите себя или зарегистрируйтесь.
Список тем
Последние темы форумов
Гальваническое цинкование металла

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

Полипропилен Бален 030, ПП 250/270. Первичное сырьё Распродажа склада.

Полипропилен Бален 030, ПП 250/270. Распродажа склада. Распродажа первичных полимеров: - Красители суперконцентраты (СКП), мастербатч...
Цена: 120 руб.

Колесо обрезиненное D-150 мм

Колеса обрезиненные D-150 мм широко используются для оснащения мангалов различных конструкций и размеров. Они позволяют легко и удобно...
Цена: 95 руб.

Оформление резидентских виз в ОАЭ. ВНЖ Дубай

Здравствуйте! Меня зовут Александра, и я помогу оформить ВНЖ и резидентскую визу в ОАЭ. Расскажу все о переезде в ОАЭ. Выполню услугу...

Разработчик .net Profit Search
70000 -
100000 руб.
Неполное среднее образование, стаж работы 3-5 лет, полная занятость
Программист-разработчик Full-Stack ГК "Kolobox"
70000 -
100000 руб.
Высшее образование, стаж работы более 5 лет, полная занятость
Frontend-разработчик Profit Search
40000 -
50000 руб.
Стаж работы 3-5 лет, частичная занятость
Программист 1С НПП ПРО-М
от 110 000 руб.
Высшее образование, стаж работы 3-5 лет, полная занятость