PDA

Просмотр полной версии : [Вопрос] Каким образом лучше всего хранить данные инвентаря в БД?



SteveStage
26.11.2019, 21:12
// DeimoS: Первая часть темы находится тут: [Вопрос] Грамотное использование switch и if (http://pro-pawn.ru/showthread.php?16987-%D0%93%D1%80%D0%B0%D0%BC%D0%BE%D1%82%D0%BD%D0%BE%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-switch-%D0%B8-if)



Создаешь отдельную таблицу, где будешь хранить ид предмета, количество, слот, id аккаунта владельца и пляшешь от них. Люди умудрялись все это записывать в одну строчку через |, поэтому твои слова, что "не получится записать" звучат смешно :)

Почему все говорят, что лучше искать по id, а не по нику?) Не понимаю, ведь id меняются, а ник нет

DeimoS
26.11.2019, 21:39
Почему все говорят, что лучше искать по id, а не по нику?) Не понимаю, ведь id меняются, а ник нет

Эмм, так речь о ID аккаунта, а не о ID игрока на сервере... Номер строки, который генерирует AI-поле.

Собственно, про то, как хранить данные в моде, тебе описали выше. При желании, всё можно реализовать так, что и столбец для хранения нового предмета будет создаваться автоматически, если его не было. Либо можно хранить каждый предмет игрока в отдельной строке - тут зависит от того, какой метод нормализации таблицы (https://ru.wikipedia.org/wiki/%D0%9D%D0%BE%D1%80%D0%BC%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D1%84%D0%BE%D1%80%D0%BC%D0%B0) выбирать.
То, что ты делаешь - крайне топорный метод, который занимает много места (а значит такой код сложнее обсуживать) и который требует кучу лишних телодвижений в случае добавления нового объекта. Но, опять же, тот метод, о котором я говорю, может быть довольно сложным без опыта и понимания того, что ты делаешь. Поэтому я бы советовал тебе пока оставить всё как есть, если оно работает, и заниматься реализацией других систем. С текущим уровнем знаний ты потратишь гораздо больше времени на переработку и решение проблем, нежели получишь профита от этого. Я эту тему озвучивал сугубо чтоб ты понимал, что можно лучше.

SteveStage
26.11.2019, 23:19
Еще раз, в бд есть столбцы slot, item и amount. А как хранить в item айди всех 3 предметов в 3 слотах? Как говорил Pa4enka, через "|"?
Допустим, но тогда столбец slot в таблице не имеет смысла, ибо предметы/их количество хранятся в столбцах item/amount, а slot в бд просто не нужен.


С текущим уровнем знаний ты потратишь гораздо больше времени на переработку и решение проблем, нежели получишь профита от этого. Я эту тему озвучивал сугубо чтоб ты понимал, что можно лучше.

Согласен, но так и познаются нюансы Pawn, на практике. Если я не начну использовать то, про что я хочу узнать подробности - я никогда этого не узнаю, ибо я не изучаю то, что не планирую использовать, такой вот я, что поделать)

Но я все таки решил попробовать сделать инвентарь с загрузкой из бд, ибо:
1. Нет идей для других систем (не баянистых)
2. Я намерен сделать эту систему максимально близкой к идеалу, на сколько у меня это может получиться

Не затруднит ли тебя дать ссылки на те темы и статьи, которые я вряд-ли найду в инете, пожалуйста? Темы на подобии этой https://pro-pawn.ru/showthread.php?8511-%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-MySQL я и так легко найду

Мне создавать отдельную тему для обсуждения этой системы, или все можно обсудить тут?

Kovshevoy
27.11.2019, 02:09
Еще раз, в бд есть столбцы slot, item и amount. А как хранить в item айди всех 3 предметов в 3 слотах? Как говорил Pa4enka, через "|"?
Допустим, но тогда столбец slot в таблице не имеет смысла, ибо предметы/их количество хранятся в столбцах item/amount, а slot в бд просто не нужен.



Согласен, но так и познаются нюансы Pawn, на практике. Если я не начну использовать то, про что я хочу узнать подробности - я никогда этого не узнаю, ибо я не изучаю то, что не планирую использовать, такой вот я, что поделать)

Но я все таки решил попробовать сделать инвентарь с загрузкой из бд, ибо:
1. Нет идей для других систем (не баянистых)
2. Я намерен сделать эту систему максимально близкой к идеалу, на сколько у меня это может получиться

Не затруднит ли тебя дать ссылки на те темы и статьи, которые я вряд-ли найду в инете, пожалуйста? Темы на подобии этой https://pro-pawn.ru/showthread.php?8511-%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-MySQL я и так легко найду

Мне создавать отдельную тему для обсуждения этой системы, или все можно обсудить тут?
Не знаю какая у тебя система инвентаря, но, лично у меня на сервере система такая, что у игрока может быть 20 предметов, у игрока еще может быть рюкзак так же на 20 предметов, инвентарь тачки/дома так же по 20 предметов. И чтобы не хранить огромное кол-во ненужных столбцов/переменных у меня под каждый слот id итема|количество и всё спокойно работает.

DeimoS
27.11.2019, 03:07
Как говорил Pa4enka, через "|"?

Так делать категорически не стоит. Вообще забудь о таком варианте хранения данных в MySQL. Это лишь усложняет работу с данными и, как следствие, замедляет получение результата.
Можно сделать либо так:
http://pro-pawn.ru/showthread.php?15221-%D0%92%D0%BE%D0%BF%D1%80%D0%BE%D1%81-%D0%BF%D1%80%D0%BE-sscanf&p=84550&viewfull=1#post84550
Либо для каждого слота создавать 2 столбца для отдельного хранения item и amount.

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




Согласен, но так и познаются нюансы Pawn, на практике. Если я не начну использовать то, про что я хочу узнать подробности - я никогда этого не узнаю, ибо я не изучаю то, что не планирую использовать, такой вот я, что поделать)

Ну так и познавай. Только в реализации других систем. Система инвентаря у тебя, как я понимаю, уже работает. Так зачем тратить время на её переработку, если можно заняться реализацией других своих идей, всё так же продолжая изучать язык, но, при этом, не топчась на месте в плане разработки.
Выбор твой, но я бы тебе советовал просто намотать на ус информацию о том, что можно лучше, и, при желании, вернулся к переработке инвентаря потом: когда появится опыт и свободное время/желание. Просто потому что все эти изменения не сказать чтобы существенны (такой код лучше, но, в идеале, его следовало писать изначально таким, понимая что ты делаешь. Вручную подгонять существующий код под новый для тебя "стиль" - это большие риски допустить ошибки и сделать только хуже). Да и когда ты создаёшь какую-то новую систему, видя результат в игре, а не где-то в сознании понимая, что ты, возможно, сделал код лучше - это гораздо сильнее стимулирует тебя к разработке и изучению нового. Так работает психология человеческая :) Впрочем, как писал - выбор твой.



1. Нет идей для других систем (не баянистых)

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


2. Я намерен сделать эту систему максимально близкой к идеалу, на сколько у меня это может получиться

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


Не затруднит ли тебя дать ссылки на те темы и статьи, которые я вряд-ли найду в инете, пожалуйста?

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


Мне создавать отдельную тему для обсуждения этой системы, или все можно обсудить тут?

Отдельную. Желательнее, вообще создавать отдельные темы для отдельных вопросов или групп вопросов, если те на схожую тему. Так, чтоб можно было дать говорящее название для темы и упростить тем самым жизнь новичкам, которые могут наткнуться на твои темы и найти для себя ответы на какие-то свои вопросы. Или чтоб можно было удобно потом сослаться на ответ к твоей теме (как, собственно, я делал выше с другими темами) и человеку не пришлось вычленять из десятка подпунктов (то бишь, не нужно перегружать одну тему вопросами) тот, который ему нужен. Правила по поводу оформления тем ведь существуют не потому что администраторам так захотелось, а как раз чтоб упростить навигацию по форуму и поиск ответов =) Соответственно, думай в том же ключе и не прогадаешь.

Pa4enka
27.11.2019, 16:02
Как говорил Pa4enka, через "|"?

Я предполагал, что это будет плохим примером ;)

Подобное оформления кода(|) не только затрудняет читаемость, но и взаимодействия с данными, которые там хранятся. Особенно придется в некотором роде "костылить" в коде сохранения, дабы обновить конкретный ид в конкретном слоте. На практике, имея набор цифр в столбце базы данных, не всегда можно сразу понять, что хотел сказать автор и что он там записывает. Особенно если в дальнейшем обвязывать мод с сайтом(админ панелью) для веб-разработчика будет проблемой без вас понять логику системы того же инвентаря. А имея отдельную таблицу с нормальной формой достаточно будет сделать выборку, вынести нужные нам данные со столбца и показать это в игре/сайте. Это действительно намного удобнее.

Если кратко:
1) При добавлении айтема -> insert into
2) При удаления айтема - удаления записи по иду слота с базы.
3) При редактировании - апдейт слота.
4) При передачи айтема другому игроку - апдейт ownerid на id "принимающего" игрока.
И так далее.

Но если ты пока не можешь понять о чем речь, то лучше оставить все как есть и довести систему до идеала в следующий раз. Как говорилось выше: в этом нет ничего плохого. Лично мне понадобилось приличное количество времени, дабы понять основы этого способа проектирования БД и несколько реализованных систем с помощью одной из нормальных форм.

DeimoS
27.11.2019, 16:30
Если кратко:
1) При добавлении айтема -> insert into
2) При удаления айтема - удаления записи по иду слота с базы.
3) При редактировании - апдейт слота.
4) При передачи айтема другому игроку - апдейт ownerid на id "принимающего" игрока.
И так далее.

В целом, это и есть описание одного из вариантов, что я выше кидал, но я бы тут избавился от удаления и просто обнулял строку в БД.
Чтоб:
1) Как можно дольше не иметь проблем с "переполнением" AI-поля (если поле будет иметь тип INT, то максимальное значение для поля будет "2147483647". Можно, конечно, сделать тип поля BIGINT, чтоб лимит стал "9223372036854775807", но с таким числом не получится работать на сервере, да и гораздо проще реализовать всё без пересоздания записей для слотов). Конечно даже лимит в "2147483647" довольно непросто достичь, но лучше сразу писать надёжный код, чем потом тратить время на восстановление его работоспособности.
2) Это позволит создавать записи для слотов при регистрации/авторизации и сразу загружать номера строк на сервер, чтоб впоследствии обновлять данные по этим номерам (ID), а не по ID аккаунта и номеру строки. Запросы будут короче и проще для MySQL.

Pa4enka
27.11.2019, 16:51
В целом, это и есть описание одного из вариантов, что я выше кидал, но я бы тут избавился от удаления и просто обнулял строку в БД.
Чтоб:
1) Как можно дольше не иметь проблем с "переполнением" AI-поля (если поле будет иметь тип INT, то максимальное значение для поля будет "2147483647". Можно, конечно, сделать тип поля BIGINT, чтоб лимит стал "9223372036854775807", но с таким числом не получится работать на сервере, да и гораздо проще реализовать всё без пересоздания записей для слотов). Конечно даже лимит в "2147483647" довольно непросто достичь, но лучше сразу писать надёжный код, чем потом тратить время на восстановление его работоспособности.
2) Это позволит создавать записи для слотов при регистрации/авторизации и сразу загружать номера строк на сервер, чтоб впоследствии обновлять данные по этим номерам (ID), а не по ID аккаунта и номеру строки. Запросы будут короче и проще для MySQL.

Кхм, интересная теория, но я не сталкивался с таким большим AI. Но если такие случае имели место быть, то действительно стоит обратить внимания на обнуления строки, правда тогда будет немного не привычно видеть много null-записей в таблице. Плюс, размер таблицы прибавится, верно?

Имхо, это уже аспекты из ряда фантастики.

DeimoS
27.11.2019, 17:17
Кхм, интересная теория, но я не сталкивался с таким большим AI. Но если такие случае имели место быть
https://habr.com/ru/post/156489/
Как пример реального описания проблем, которые могут возникнуть в этом случае :)



правда тогда будет немного не привычно видеть много null-записей в таблице.

Эмм, создаёшь столбец с флагом NOT NULL и таблица трактует все NULL значения как 0. В итоге вместо NULL/пустых записей будешь видеть нули :) И то только в последних двух столбцах: ID предмета и количество. Слот и ID аккаунта нулями не будут.


Плюс, размер таблицы прибавится, верно?

Если критичен размер таблицы, то стоит вместо создания отдельной записи под каждый слот создавать столбцы =) Тогда инвентарь одного игрока будет умещаться в одну запись. О чём я, собственно, писал ранее.
Автоматизировать подобный вариант можно точно так же, как и вариант с созданием отдельной строки под каждый слот.
А вообще особой разницы в размере не будет. По крайней мере она точно будет несущественной в сравнении со всеми плюсами.

execution
27.11.2019, 18:24
DeimoS, пользуясь случаем, хотел уточнить. Если использовать 1 вариант (создание строки под каждый итем), следовательно при регистрации создавать столько строк, столько количество может быть итемов. Но это ж может быть до 30 INSERT запросов, не затратно ли? Или же есть более продуктивный способ?

Pa4enka
27.11.2019, 18:41
DeimoS, пользуясь случаем, хотел уточнить. Если использовать 1 вариант (создание строки под каждый итем), следовательно при регистрации создавать столько строк, столько количество может быть итемов. Но это ж может быть до 30 INSERT запросов, не затратно ли? Или же есть более продуктивный способ?

Зачем?

> Запрос в таблицу.
> Если данные не найдены(insert не юзался) - рисуешь пустые ячейки.
> Если БД вернула больше 1 строки - заполняешь ячейку нужным айтемом.

В общем, если данные в базе отсутствуют, то "по дефолту" ячейка инвентаря будет пустой.

execution
27.11.2019, 18:49
Зачем?

> Запрос в таблицу.
> Если данные не найдены(insert не юзался) - рисуешь пустые ячейки.
> Если БД вернула больше 1 строки - заполняешь ячейку нужным айтемом.



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

Pa4enka
27.11.2019, 19:02
Ну тогда в твоём случае, следует очищать при коннекте массив с данными инвентаря и, задавать например, значение, характеризующее, что данный слот не был загружен.


В общем, если данные в базе отсутствуют, то "по дефолту" ячейка инвентаря будет пустой.
База в данном случае хранит существующие(!) айтемы игроков. Всё остальное - пустые ячейки. Спрашивается, зачем они нужны в базе?


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

execution
27.11.2019, 19:17
База в данном случае хранит существующие(!) айтемы игроков. Всё остальное - пустые ячейки. Спрашивается, зачем они нужны в базе?

Это был как пример.

- - - Добавлено - - -



Ну так заполни все слоты, которых нет в базе, при регистрации нулями, к примеру, либо -1. Смотря как у тебя обозначаются пустые слоты. И не нужно будет ничего проверять, ибо у тебя всегда будет актуальная информация и на сервере и в базе.

А теперь посмотри вопрос, который я ставил.

DeimoS
27.11.2019, 19:52
DeimoS, пользуясь случаем, хотел уточнить. Если использовать 1 вариант (создание строки под каждый итем), следовательно при регистрации создавать столько строк, столько количество может быть итемов. Но это ж может быть до 30 INSERT запросов, не затратно ли? Или же есть более продуктивный способ?

А теперь сделай бэкап какой-нибудь своей заполненной таблицы (или скачай мод с бэкапом БД) и посмотри на структуру запросов :)
MySQL способна по несколько тысяч записей создавать за секунду без каких-либо трудностей. И это без какой-либо специфичной настройки под конкретное железо, что может увеличить скорость работы MySQL.
Так что нет, проблем от 30 запросов не будет :)

И да, я имею ввиду именно то, что в БД создаются записи для хранения предметов сразу при регистрации, а не по мере поступления данных. Просто потому что второй вариант будет требовать от тебя проверки существования этих самых данных: то бишь, каждое обновление какого-либо из слотов тебе нужно будет отправить сначала SELECT-запрос, а только потом отправить UPDATE или INSERT. Гораздо проще и надёжнее реализовать создание строк прямо при регистрации (и при авторизации так же проверять существование записей под каждый слот).

Стоит понимать две простых истины:
1) Вы тут не микропроцессоры программируете и у вас нет сильных ограничений по доступной для использования памяти. Так что нет никакого смысла экономить ей, урезая, при этом, скорость работы и надёжность системы (от которой напрямую зависит то, будете ли вы тратить время на создание новых систем или на исправление багов в уже написанных системах). UPD: И да, это применимо только в случае, когда память используется по делу :) Как, например, в нашем случае.
2) Размер такой таблицы даже с миллионом записей будет каким-то уж очень большим. А, при желании, можно прикрутить и перенос старых данных в дочернюю таблицу (либо их удаление). Хотя, опять же, непонятно на каких калькуляторах нужно запускать MySQL-сервер, чтоб размер столь простых таблиц смог создать хоть какие-то проблемы. MySQL наоборот создали для того, чтоб иметь возможность быстро работать с данными, тратя, при этом, дополнительную память (если уж совсем в дебри не зарываться, то индексы - отличный пример того, как жертвуя памятью мы можем получить существенный прирост к скорости, если сделаем всё правильно).

- - - Добавлено - - -

Ну и да: я бы всё же советовал использовать в данном случае вариант со столбцами под слоты и одной записью в таблице для одного игрока, а не "1 слот = 1 строка". Вариант с построчным заполнением хорош в системах, которые могут часто изменяться или сами по себе требуют гибкого количества записей (например, если вы решите сделать так, что за донат можно купить любое количество слотов, то да, вариант с "1 слот = 1 строка" - идеальный). В данном же случае гораздо проще и вам, и MySQL будет, если данные игрока будут хранится в одной строке.

Просто научитесь пользоваться оператором "ALTER TABLE" (или просто тупо делайте нужные изменения в таблице, а потом делайте её бэкап и смотрите какой код запросов вам сгенерирует phpMyAdmin) и тогда сможете сделать вариант с одной записью на игрока таким же гибким, как и вариант "1 слот = 1 строка".
Запрос на проверку существования столбца тоже выглядит просто:
SHOW COLUMS FROM `имя_таблицы` WHERE `Field` = 'имя столбца'
Без "WHERE", соответственно, выдаст просто структуру таблицы и можно будет проверить существование столбцов на стороне сервера (хотя можно и форматирование запроса сделать соответствующе, чтоб сама MySQL всё проверила и вернула лишь "1" или "0"). Собственно, проверяете существование столбцов и если каких-то не хватает (а так будет только если вы решите добавить новые столбцы) - добавляете их через "ALTER TABLE".
В общем, этот способ можно сделать столь же гибким, но он, при этом, будет гораздо экономичнее и проще. Вся основная нагрузка будет сконцентрирована только при старте сервера. А выгружать и обновлять придётся одну единственную строку во всех случаях. Соответственно, создав составной индекс на поля с AI и ID аккаунта вы получите хорошую производительность и, при этом, компактность (для инвентаря с 30 слотами такой вариант будет содержать на 58 записей меньше, ибо не нужно будет для каждого слота дублировать номер строки и ID аккаунта. То бишь: "(количество слотов - 1) * 2").

SteveStage
28.11.2019, 19:48
Можно сделать либо так:
http://pro-pawn.ru/showthread.php?15221-%D0%92%D0%BE%D0%BF%D1%80%D0%BE%D1%81-%D0%BF%D1%80%D0%BE-sscanf&p=84550&viewfull=1#post84550

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

1 вариант и был у меня изначально (только в бд с аккаунтами), а 2 вариант довольно интересный...
Я думал, что значения для каждого игрока будут в 1 строку со значениями, а тут на каждый слот своя строка в бд, вот этого варианта инвентаря я точно не учел

UPD: Я вернул все как было, только теперь у инвентаря своя таблица (вариант с столбцами под каждый слот), да и он в моде будет выглядеть проще (вместо постоянных sscanf и создания переменных под каждый предмет и количество в слоте, это будет храниться в энуме)

DeimoS
28.11.2019, 21:26
Вопрос решён?

SteveStage
28.11.2019, 21:31
Да, спасибо за то, что не поленился и вынес все ключевые сообщения в отдельную тему.