|
Принятые патчи Иногда выкладывают патчи, которые потом в итоге все-таки принимают в ядро.
Повод для гордости. |
|
Опции темы | Поиск в этой теме | Опции просмотра |
05.03.2011, 11:52 | #1 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
[11284]Prepared statements for MySQL [part 1]
Всем трямс
Вобщем, как и обещалось некоторое время назад, поддержка для prepared statements в мангосе таки появится Для тех, кто незнает, что сие такое и зачем оно вообще надо, могут погуглить - многа букаф писать на выходных я не осилю )) На данном этапе реализована поддержка для INSERT+DELETE+UPDATE запросов. SELECTы будут реализованы позднее, дабы не коммитить патчи монструозного размера. Важный момент: нативные prepared statements реализованы только для MySQL. Пользователи PostgreSQL будут пользоваться эмуляцией этой функциональности, которая будет сводится к отправке обычных строковых запросов к БД. На данный момент переписаны все запросы, которые используются во время сохранения игрока, e.g. вызова функции Player::SaveToDB(). WARNING: СДЕЛАЙТЕ БЕКАП БАЗЫ ДО НАЧАЛА ТЕСТОВ!!! Ссылка на тему на офф форуме: http://getmangos.com/community/post/132464/ репозиторий: prepared_statements update #1: добавлена поддержка PostgreSQL. Финальная версия патча. update #2: ODBC-похожий АПИ для передачи параметров процедурам. update #3: правка ошибок компиляции под *nix update #4: правка синтаксиса некоторых запросов. update #5: переписан код всвязи с найденными критическими нюансами инициализации статических переменных функций в многопоточной среде. Спасибо Vinolentus. Ожидайте незначительного увеличения потребления CPU из-за постоянного поиска в реесте нужных хранимых процедур по строке запроса. update #6: переписан код, теперь мы корректно используем статические локальные переменные для хранения информации по процедурам. Должно вернуть потребление ЦП к норме. Последний раз редактировалось Ambal; 19.03.2011 в 22:48. |
05.03.2011, 12:19 | #2 |
WowCore Dev
Регистрация: 31.03.2010
Сообщений: 468
Сказал(а) спасибо: 73
Поблагодарили 106 раз(а) в 70 сообщениях
|
погуглил. а, вот как это называется
цитирую: http://itdumka.com.ua/index.php?cmd=shownode&node=17 или если не открывается: http://hghltd.yandex.net/yandbtm?fmo...83d9b8&keyno=0 у себя такое тоже сделано, только я не заметил никакого прироста скорости, производительности и чего там еще ожидалось. |
05.03.2011, 12:29 | #3 |
Пользователь
Регистрация: 12.03.2010
Сообщений: 85
Сказал(а) спасибо: 5
Поблагодарили 42 раз(а) в 17 сообщениях
|
грац Ж)
|
05.03.2011, 12:54 | #4 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
RomanRom2, опыт использования prepared statements в РНР к мангосу никакого отношения не имеет Мы повторно используем наши подготовленные процедуры, так что выигрыш будет в любом случае:
http://euedge.com/blog/2007/11/11/pr...ance-in-mysql/ http://rubayeet.wordpress.com/2008/1...hp-experiment/ P.S. RomanRom2, в статье, что вы привели, деятель каждый раз в функции function workWithPS() подготавливает процедуры при каждом ее вызове - не удивительно, что у него все тормозит )) function workWithPS() { $stmt = $db->prepare('Select ID from USERS where LOGIN = ? and EMAIL = ?'); .... $stmt->close(); } Последний раз редактировалось Ambal; 05.03.2011 в 13:02. |
Пользователь сказал cпасибо: | Vinolentus (11.03.2011) |
05.03.2011, 13:13 | #5 |
WowCore Dev
Регистрация: 31.03.2010
Сообщений: 468
Сказал(а) спасибо: 73
Поблагодарили 106 раз(а) в 70 сообщениях
|
Ambal, всё может быть. я не против "новых технологий" и их внедрения, тем самым повышая качество кода. наоборот, даже за, важно только этим не увлечься
уверен, что хуже точно не станет. а что касается статьи, это первое что у меня открылось по теме и сразу вот так, в точку можно сказать |
05.03.2011, 16:06 | #6 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Добавил поддержку PostgreSQL - prepared statements будет эмулироваться отправкой обычных строковых запросов. На большее любители этой DBMS от меня пусть не расчитывают
|
Пользователь сказал cпасибо: | Konctantin (11.03.2011) |
05.03.2011, 18:26 | #7 | |
Почетный флудер
Старожил
Регистрация: 08.03.2010
Адрес: Мурманск, Россия
Сообщений: 788
Сказал(а) спасибо: 55
Поблагодарили 333 раз(а) в 151 сообщениях
Записей в дневнике: 1
|
Цитата:
|
|
11.03.2011, 10:00 | #8 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Множество изменений в коде за последние несколько дней, а также правка найденных багов и ошибок компиляции под никсами.
|
2 пользователя(ей) сказали cпасибо: | Den (11.03.2011), Konctantin (11.03.2011) |
12.03.2011, 06:08 | #9 |
Пользователь
Регистрация: 07.03.2010
Сообщений: 46
Сказал(а) спасибо: 11
Поблагодарили 17 раз(а) в 11 сообщениях
|
Код:
for (int k = 0; k < MAX_EFFECT_INDEX; ++k) insertAuras.addInt32(damage[k]); for (int k = 0; k < MAX_EFFECT_INDEX; ++k) insertAuras.addInt32(maxduration[k]); for (int k = 0; k < MAX_EFFECT_INDEX; ++k) insertAuras.addInt32(remaintime[k]); Код:
for (int k = 0; k < MAX_EFFECT_INDEX; ++k) { insertAuras.addInt32(damage[k]); insertAuras.addInt32(maxduration[k]); insertAuras.addInt32(remaintime[k]); } |
Пользователь сказал cпасибо: | Ambal (12.03.2011) |
12.03.2011, 09:20 | #10 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
ghostpast, я пока не собираюсь переписывать сами запросы к базе данных. Если у вас будет желание, то как патч будет закоммичен, можете переписать запросы к базе "покрасивше"
Тестеры с офф сайта говорят, что с последней версией патча при 1к онлайна с mtmaps проблем не замечено, так что можете пробовать. |
12.03.2011, 15:56 | #11 |
Пользователь
Регистрация: 23.03.2010
Сообщений: 51
Сказал(а) спасибо: 14
Поблагодарили 32 раз(а) в 15 сообщениях
|
Ambal, а что произойдет, если один и тот же статик стэйтмент в каком-то одном потоке уже запрошен, но еще не создан в Database::CreateStatement, и в этот момент к нему подходит другой поток?
|
12.03.2011, 17:11 | #12 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Мы со статическими переменными рискуем только несколько раз вызвать конструктор/код инициализации для нашего объекта из разных потоков - компилятор создает глобальные переменные, которые используются для вычисления, был ли проинициализирован объект или нет. В нашем случае, мы ничем не рискуем, т.к. в SqlStatement используются встроенные типы, которые получают одни и теже значения при каждом вызове.
Это было сделано ради того, чтобы: 1) закешировать информацию по процедуре, а не возиться с поиском по реестру; 2) иметь возможность создавать объекты SqlStatement в любом месте кода, не не возиться напрямую с айдишниками и различными дефайнами как это сделано, например, в TrinityCore. P.S. Я лично никого не воодушевляю на подобную практику со статическими переменными в функциях - слишком много подводных камней при инициализации. |
12.03.2011, 17:28 | #13 | |
Пользователь
Регистрация: 23.03.2010
Сообщений: 51
Сказал(а) спасибо: 14
Поблагодарили 32 раз(а) в 15 сообщениях
|
Цитата:
|
|
12.03.2011, 18:38 | #14 | |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Цитата:
UPDATE: провел собственное расследование: незнаю, какой жопой думали в Майкрософте разработчики компилятора, но таки компилятор отлавливает только первое обращение, а не момент инициализации. Если вы запустите программу http://paste2.org/p/1298414, то получите результат: Код:
Obtained value = 0 I'm the object constructor Obtained value = 1 Так что чую буду переписывать всю эту писанину P.S. Моя в полнейшем ах...е Последний раз редактировалось Ambal; 12.03.2011 в 19:15. |
|
12.03.2011, 20:34 | #15 |
Пользователь
Регистрация: 23.03.2010
Сообщений: 51
Сказал(а) спасибо: 14
Поблагодарили 32 раз(а) в 15 сообщениях
|
|
12.03.2011, 21:09 | #16 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Как бы там нибыло, патч я переделал с учетом "особенностей национальной инициализации статических переменных функций в С++". Пока будет использоваться поиск по реестру при создании объектов SqlStatement. Чуть позже подумаю, как корректно сделать нормальный вызов процедур по их айди.
Последний раз редактировалось Ambal; 12.03.2011 в 21:11. |
14.03.2011, 10:57 | #17 |
Умный
Регистрация: 02.07.2010
Сообщений: 434
Сказал(а) спасибо: 27
Поблагодарили 73 раз(а) в 45 сообщениях
|
как насчет того что бы использовать критическую секцию для доступа к данным класса ? вообще такое программирование многопоточных классов без использования объектов синхронизации чревато ...
И какой смысл вкладывался в выделенную строчку ? Хотели что бы переменная _obj существовала в памяти в единственном экземпляре ? Код:
static DWORD WINAPI ThreadFunc(LPVOID param) { static Object _obj(Object::init()); _obj.Print(); return 0; } Последний раз редактировалось Йоха; 14.03.2011 в 11:16. |
14.03.2011, 12:08 | #18 | |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Цитата:
Есть другое предложение по поводу использования статических локальных переменных. Код:
SqlStatement Database::CreateStatement(SqlStatementID& index, const char * fmt) { if(!index.initialized()) index = AllocIndex(fmt); return SqlStatement(index, *this); } ... static SqlStatementID index; SqlStatement request = CharacterDatabase.CreateStatement(index, "SELECT * FROM table"); Мысли, возражения? |
|
14.03.2011, 15:45 | #19 |
Умный
Регистрация: 02.07.2010
Сообщений: 434
Сказал(а) спасибо: 27
Поблагодарили 73 раз(а) в 45 сообщениях
|
что-то тут не то с дизайном приложения ...
какой смысл инициализировать статическую переменную значением параметра передаваемую в функцию-член ? ведь по такой логике этот параметр будет игнорироваться во всех остальных случаях кроме первого раза. если я правильно понял идею то по моему это должно выглядеть примерно так: Код:
class Database; class SqlStatementID { public: SqlStatementID(){}; ~SqlStatementID(){}; }; class SqlStatement { public: SqlStatement(){}; SqlStatement(SqlStatementID& index, Database *db){}; ~SqlStatement(){}; }; class Database { public: Database(void){}; ~Database(void){}; SqlStatement CreateStatement(const char *fmt) { return SqlStatement(m_index, this); }; static SqlStatementID m_index; }; SqlStatementID AllocIndex() { return SqlStatementID(); } // инициализация статической переменной SqlStatementID Database::m_index = AllocIndex(); int _tmain(int argc, _TCHAR* argv[]) { Database CharacterDatabase; SqlStatement request = CharacterDatabase.CreateStatement("SELECT * FROM table"); return 0; } |
14.03.2011, 16:46 | #20 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
так это именно то, что нам и нужно - проинициализировать переменную нужными нам значениями, а потом просто использовать этот объект как локальный кеш данных дабы не гонять поиск по хеш-таблице постоянно.
|
14.03.2011, 17:02 | #21 |
Умный
Регистрация: 02.07.2010
Сообщений: 434
Сказал(а) спасибо: 27
Поблагодарили 73 раз(а) в 45 сообщениях
|
тут или я что-то не понимаю ... или в логике ошибка
если нужен кеш, то почему он должен быть один на все экземпляры класса ? кеш что кеширует ? данные экземпляра ? или все экземпляры содержат одинаковые данные ? если это действительно какой-то кеш который один на все возможные экземпляры класса, то он инициализируется 1 раз не из ран-тайма, а в компил-тайм, вроде того что я привел пример выше. В общем для меня слишком много непонятного, опишите ситуацию целиком если не трудно P.S. к тому же какой смысл объявлять глобальную переменную как статик ? глобальные переменные и так существуют в единственном экземпляре Последний раз редактировалось Йоха; 14.03.2011 в 17:23. |
14.03.2011, 17:24 | #22 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Йоха, мы инициализируем локальную статическую переменную функции, а не член класса
Код:
void Function() { static SqlStatementID index; SqlStatement request = CharacterDatabase.CreateStatement(index, "INSERT INTO table"); request.Execute(); } Поэтому не вижу причин для паники. |
14.03.2011, 19:47 | #23 | |
Умный
Регистрация: 02.07.2010
Сообщений: 434
Сказал(а) спасибо: 27
Поблагодарили 73 раз(а) в 45 сообщениях
|
Цитата:
если нужен перечень айди и еще какие-то параметры, почему бы не создать некий класс - менеджер этих данных и кэшировать их внутри нормальными способами, и не городить какие-то костыли с неопределенным поведением Последний раз редактировалось Йоха; 14.03.2011 в 19:59. |
|
14.03.2011, 21:50 | #24 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Йоха, менеджер уже сейчас есть и используется. Только вот постоянный поиск по хеш-таблице ради нужных даных по запросу - занятие довольно таки затратное, отчасти виной тому наши странные хеширующие функции для строк. При текущих 90 запросах мы имеем увеличение загрузки ЦП на 6-10%. А таких запросов при поддержке SELECTов будет порядка 150-200.
|
14.03.2011, 22:57 | #25 |
Умный
Регистрация: 02.07.2010
Сообщений: 434
Сказал(а) спасибо: 27
Поблагодарили 73 раз(а) в 45 сообщениях
|
ну при таком подходе других вариантов нет, к тому же возможно затраты на поиск нужного prepared statement для строки запроса сведет на нет выигрыш от использования самих prepared statements. Тут придется только искать способ максимально быстро находить PS соответствующий sql выражению
|
19.03.2011, 22:47 | #26 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Переделал патч, теперь траблов не должно быть с использованием статических локальных переменных. Объекты класса SqlStatementID теперь должны обеспечивать нужное нам поведение. Пробуйте.
|
4 пользователя(ей) сказали cпасибо: |
23.03.2011, 14:11 | #28 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Я планирую закоммитить патч в течение ближайшей недели в случае если не будут найдены проблемы в коде. На серверах с 1к+ онлайна ошибок на данный момент не обнаружено, поэтому можете начинать тестировать добровольно пока у вас есть время
|
Пользователь сказал cпасибо: | Konctantin (23.03.2011) |
24.03.2011, 09:10 | #29 |
MaNGOS Dev
Регистрация: 22.06.2010
Сообщений: 78
Сказал(а) спасибо: 24
Поблагодарили 71 раз(а) в 25 сообщениях
|
Всем, кому интересна статистика с сервера MySQL, что обслуживает мангос с prepared statements, могут взглянуть на скриншот:
Доля PS теперь занимает 42% на сервере (поправьте если неправильно интерпретирую результаты). И это благодаря только 90 запросам из почти 900 в чистом ядре Цифра может отличаться от чистого мангоса, т.к. у тестировщика очень много сторонних патчей. fgenesis готовит патч, который позволит собрать статистику по каждому запросу к БД чтобы мы могли перевести на PS только критические для быстродействия запросы. Последний раз редактировалось Ambal; 24.03.2011 в 09:37. |
|
|
Похожие темы | ||||
Тема | Автор | Раздел | Ответов | Последнее сообщение |
[11284] Implement prepared statements for INSERT+DELETE+UPDATE SQL requests. Should improve player s | newsbot | CMaNGOS Commits | 0 | 25.03.2011 22:20 |
[11061] Bring 'autocommit' mode for MySQL back. This MySQL feature operates in so frustrating way so | newsbot | CMaNGOS Commits | 0 | 21.01.2011 23:52 |
ошибка mysql | lovepsone | Флудильня | 8 | 14.12.2010 22:13 |
Оптимизация Mysql {my.cnf} | lina | Прочая документация | 10 | 20.06.2010 00:12 |