Popular Post N1kS Posted October 19, 2016 Popular Post Share Posted October 19, 2016 (edited) Данный урок предполагает, что вы уже знаете, что такое MySQL, как это работает и зачем это нужно, если же нет - ознакомитесь с данным уроком и вернитесь сюда! Цель данного урока - донести до вас некоторые вещи, которые вы, возможно, не понимаете или даже не задумывались о них. Немного теории MySQL - свободная реляционная система управления базами данных. Для работы с базой используется язык структурированных запросов(он же SQL). Более подробную и интересующую Вас информацию об SQL, Вы сможете найти на просторах интернета. Мы же поговорим о ключевых моментах работы с MySQL. SQL имеет 4 основных оператора для манипуляции с данными. SELECT - выбор данных, удовлетворяющих заданные условия. INSERT - добавление новых данных. UPDATE - изменение существующих данных. DELETE - удаление указанных данных Я не буду рассказывать вам о существующих типах данных MySQL, как создавать или удалять таблицы, я лишь хочу поделиться с вами ключевыми вещами, которые помогут вам оптимизировать работу вашего сервера и уменьшить нагрузку на него. Рассмотрим на основе примера В качестве примера для данного урока будет использоваться таблица с названием players, имеющая следующие столбцы: `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `surname` varchar(255) NOT NULL, `age` tinyint(3) NOT NULL, `adminLevel` tinyint(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) Тут я думаю все понятно, никаких проблем быть не должно. Для примера рассмотрим несколько запросов. Получаем всех игроков: SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` Получаем игрока с конкретным id: SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE id=117 Получаем всех игроков, имя которых равно какому-то конкретному значению: SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE name="Bobby" Получаем первых 10 игроков, возраст которых равен 19 лет: SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE age=19 LIMIT 10 Получаем всех игроков, возраст которых больше или равен 18 годам: SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE age >= 18 Ну тут все просто, пришло время рассмотреть все на основе конкретных примеров и указать ключевые особенности. Неправильный выбор функции для формирования запроса Это первая и наиболее часто встречающаяся ошибка, которую я вижу в коде различных разработчиков. Для формирования запроса к MySQL в МТА существует 2 функции, а именно: dbExec и dbQuery. Обе функции выполняют запрос, но их главная особенность заключается в том, что dbQuery возвращает какой-либо результат и тем самым занимает оперативную память сервера, а dbExec нет. Очень часто разработчики забывают использовать dbFree после запроса, для создания, редактирования или удаления какой-то записи. Рассмотрим на основе простого примера создания нового пользователя: local Name = "Bobby" local Surname = "Raily" local Age = 23 dbExec(dbConnection, "INSERT INTO `players` (name, surname, age) VALUES(?, ?, ?)", Name, Surname, Age) Опять же, все просто, сформировали простой запрос, создали новую запись в таблице players с заданными значениями. Можно, конечно, реализовать это с помощью dbQuery, но обязательно не стоит забывать про dbFree! Казалось бы, а что такого? Но все дело в том, что если у вас на сервере зарегистрируется большое количество игроков, то это порядком забьет память ненужной ерундой, проще говоря мусором, который хранить на сервере нет никакой необходимости. local Name = "Bobby" local Surname = "Raily" local Age = 23 local Query = dbQuery(dbConnection, "INSERT INTO `players` (name, surname, age) VALUES(?, ?, ?)", Name, Surname, Age) dbFree(Query) Я надеюсь, что вы четко и ясно уяснили для себя этот пункт, на это стоит обратить особое внимание. Некорректное использование dbQuery для получения результата запроса Очень часто вам необходимо получить какие-то данные из базы данных. В этом нам помогают dbQuery и dbPoll. Если внимательно посмотреть на синтаксис функции dbQuery, то вы увидите, что в качестве первого необязательного аргумента она принимает callback функцию. Что же это такое и зачем это нужно? Я настоятельно рекомендую вам как можно внимательнее и ответственнее подойти к этому вопросу, т.к. многие разработчики до сих пор не до конца уловили суть данного аргумента и не понимают из-за чего происходят "фризы" во время работы того или иного скрипта. Предположим, что у нас зарегистрировано 100 000 уникальных игроков(для крупного проекта - вполне себе реально, но мы рассматриваем все в теории). Нам необходимо получить список всех имеющихся игроков. Вы должны понимать, что это не произойдет моментально, в любом случае на данную операцию будет затрачено какое-то количество времени. Рассмотрим два примера, использование запроса без callback функции и с ней соответственно: local Players = dbPoll(dbQuery(dbConnection, "SELECT * FROM `players`"), -1) for Index, PlayerData in ipairs(Players) do print(PlayerData.name) end function CallbackFunction(qh, tag, score) local Players = dbPoll(qh, 0) for Index, PlayerData in ipairs(Players) do print(PlayerData.name) end end dbQuery(CallbackFunction, dbConnection, "SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players`") Время, занявшее на выполнение данного запроса, составило 489 мс. Так в чем же характерная особенность между первым и вторым способом? Особенность заключается в том, что пока выполняется получение данных из базы первым способом, то работа нашего сервера приостановиться на время, которое необходимо для выполнения данного запроса, что может негативно повлиять на всех игроков, в результате могут возникнуть такие вещи как фризы, рассинхронизация и т.д. Поэтому вы четко должны понимать для себя нужно вам это или нет. Если же вам необходимо, чтобы работа сервера была приостановлена на время выполнения запроса - используйте первый вариант, если же нет - второй. Если же вы до этого имели опыт с другими ЯП, то вероятнее всего понимаете, что такое синхронное и асинхронное выполнение. Первый вариант - это синхронное выполнение, второй - асинхронное. Выполнение лишней работы посредством Lua Так же очень часто наблюдаю картину, когда многие разработчики выполняют лишнюю работу, а именно предпринимают лишние действия, которые можно было сформировать в результате SQL запроса. SQL существует довольно большое количество времени и за это время овладел всеми необходимыми функциями, операторами и прочими вещами для формирование корректного запроса. К примеру мы хотим получить id всех игроков, adminLevel которых выше или равен 2. Как видно из запроса - мы сразу же получаем список игроков, уровень которых равен или больше 2 function CallbackFunction(qh, tag, score) local Players = dbPoll(qh, 0) for Index, PlayerData in ipairs(Players) do print(PlayerData.id) end end dbQuery(CallbackFunction, dbConnection, "SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE adminLevel >= 2") Но иногда мне приходится видеть, как некоторые разработчики получают список всех игроков и начинают проверь их adminLevel посредством Lua, что само по себе не имеет никакого смысла, т.к это выполнение лишней работы. function CallbackFunction(qh, tag, score) local Players = dbPoll(qh, 0) for Index, PlayerData in ipairs(Players) do if PlayerData.adminLevel >= 2 then print(PlayerData.id) end end end dbQuery(CallbackFunction, dbConnection, "SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players`") Заключение Надеюсь, что вы не зря потратили свое время и подчеркнули для себя какие-то полезные вещи, которые в последствии помогут вам при разработке собственного игрового режима или мода. Если же у вас остались какие то вопросы или вам что-то непонятно - вы можете оставлять свои вопросы в данной теме. Edited December 16, 2016 by N1kS 5 Link to comment
Kernell Posted October 20, 2016 Share Posted October 20, 2016 (edited) Никогда не используйте SELECT * в своих проектах, всегда указывайте реально нужные поля для выборки. Edited October 20, 2016 by Kernell 3 Link to comment
N1kS Posted October 20, 2016 Author Share Posted October 20, 2016 (edited) 47 minutes ago, Kernell said: Никогда не используйте SELECT * в своих проектах, всегда указывайте реально нужные поля для выборки. Предположим(по примеру), что мне необходимо получить id, name, surname, age, adminLevel конкретного игрока, зачем мне указывать конкретные поля для выборки, если * - это и есть все необходимые поля? Другой вопрос, если при создании таблицы создаются дополнительные колонки, например created_at, updated_at, которые нам знать не нужно. В таком случае - да, это замедлит скорость запроса, да и мы забьем память совершенно не нужной нам информацией. SELECT * FROM `players` WHERE id=1 SELECT `id`, `name`, `surname`, `age`, `adminLevel` FROM `players` WHERE id=1 Совет совершенно верный, но лишь для частных случаев. Всегда нужно понимать, какие поля необходимы в конечном результате запроса. Чуть позже обновлю тему и допишу данный совет. Edited October 20, 2016 by N1kS Link to comment
Kernell Posted October 20, 2016 Share Posted October 20, 2016 (edited) 41 minutes ago, N1kS said: зачем мне указывать конкретные поля для выборки, если * - это и есть все необходимые поля? 1. Оптимизация. Лишняя трата ресурсов (сначала БД будет составлять список полей для запроса). 2. Улучшает читабельность кода - сразу прослеживается структура таблицы. 3. Избавит вас от ошибок типа "удалили поле в бд, а в коде оно где-то используется и не заметили". 4. Таблица может расширяться, это приведёт к передаче не нужных данных. Edited October 20, 2016 by Kernell 1 Link to comment
Maladoy.16 Posted March 12, 2020 Share Posted March 12, 2020 [2020-03-12 14:44:00] WARNING: [gameplay]\mysql\server.Lua:8: Bad usage @ 'dbConnect' [Can't connect to MySQL server on 'localhost' (10061)] [2020-03-12 14:44:00] ERROR: [gameplay]\mysql\server.Lua:12: [MYSQL][ERROR] Connection failed! [2020-03-12 14:44:08] WARNING: [gameplay]\mysql\server.Lua:8: Bad usage @ 'dbConnect' [Can't connect to MySQL server on 'localhost' (10061)] [2020-03-12 14:44:08] ERROR: [gameplay]\mysql\server.Lua:12: [MYSQL][ERROR] Connection failed! [2020-03-12 14:44:08] WARNING: [gameplay]\mysql\server.Lua:35: Bad argument @ 'dbQuery' [Expected db-connection at argument 3, got boolean] [2020-03-12 14:44:15] WARNING: [gameplay]\mysql\server.Lua:8: Bad usage @ 'dbConnect' [Can't connect to MySQL server on 'localhost' (10061)] [2020-03-12 14:44:15] ERROR: [gameplay]\mysql\server.Lua:12: [MYSQL][ERROR] Connection failed! [2020-03-12 14:44:22] WARNING: [gameplay]\mysql\server.Lua:8: Bad usage @ 'dbConnect' [Can't connect to MySQL server on 'localhost' (10061)] [2020-03-12 14:44:22] ERROR: [gameplay]\mysql\server.Lua:12: [MYSQL][ERROR] Connection failed! kak mne s etim spravitsa? mojno pomoci Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now