[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: переписан код, теперь мы корректно используем статические локальные переменные для хранения информации по процедурам. Должно вернуть потребление ЦП к норме. |
Цитата:
цитирую: http://itdumka.com.ua/index.php?cmd=shownode&node=17 или если не открывается: http://hghltd.yandex.net/yandbtm?fmo...83d9b8&keyno=0 у себя такое тоже сделано, только я не заметил никакого прироста скорости, производительности и чего там еще ожидалось. |
грац Ж)
|
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, всё может быть. я не против "новых технологий" и их внедрения, тем самым повышая качество кода. наоборот, даже за, важно только этим не увлечься :)
уверен, что хуже точно не станет. а что касается статьи, это первое что у меня открылось по теме и сразу вот так, в точку можно сказать :) |
Добавил поддержку PostgreSQL - prepared statements будет эмулироваться отправкой обычных строковых запросов. На большее любители этой DBMS от меня пусть не расчитывают :)
|
Цитата:
|
Множество изменений в коде за последние несколько дней, а также правка найденных багов и ошибок компиляции под никсами.
|
Код:
for (int k = 0; k < MAX_EFFECT_INDEX; ++k) Код:
for (int k = 0; k < MAX_EFFECT_INDEX; ++k) |
ghostpast, я пока не собираюсь переписывать сами запросы к базе данных. Если у вас будет желание, то как патч будет закоммичен, можете переписать запросы к базе "покрасивше" :)
Тестеры с офф сайта говорят, что с последней версией патча при 1к онлайна с mtmaps проблем не замечено, так что можете пробовать. |
Ambal, а что произойдет, если один и тот же статик стэйтмент в каком-то одном потоке уже запрошен, но еще не создан в Database::CreateStatement, и в этот момент к нему подходит другой поток?
|
Мы со статическими переменными рискуем только несколько раз вызвать конструктор/код инициализации для нашего объекта из разных потоков - компилятор создает глобальные переменные, которые используются для вычисления, был ли проинициализирован объект или нет. В нашем случае, мы ничем не рискуем, т.к. в SqlStatement используются встроенные типы, которые получают одни и теже значения при каждом вызове.
Это было сделано ради того, чтобы: 1) закешировать информацию по процедуре, а не возиться с поиском по реестру; 2) иметь возможность создавать объекты SqlStatement в любом месте кода, не не возиться напрямую с айдишниками и различными дефайнами как это сделано, например, в TrinityCore. P.S. Я лично никого не воодушевляю на подобную практику со статическими переменными в функциях - слишком много подводных камней при инициализации. |
Цитата:
|
Цитата:
UPDATE: провел собственное расследование: незнаю, какой жопой думали в Майкрософте разработчики компилятора, но таки компилятор отлавливает только первое обращение, а не момент инициализации. Если вы запустите программу http://paste2.org/p/1298414, то получите результат: Код:
Obtained value = 0 Так что чую буду переписывать всю эту писанину :) P.S. Моя в полнейшем ах...е |
|
Как бы там нибыло, патч я переделал с учетом "особенностей национальной инициализации статических переменных функций в С++". Пока будет использоваться поиск по реестру при создании объектов SqlStatement. Чуть позже подумаю, как корректно сделать нормальный вызов процедур по их айди.
|
как насчет того что бы использовать критическую секцию для доступа к данным класса ? вообще такое программирование многопоточных классов без использования объектов синхронизации чревато ...
И какой смысл вкладывался в выделенную строчку ? Хотели что бы переменная _obj существовала в памяти в единственном экземпляре ? Код:
static DWORD WINAPI ThreadFunc(LPVOID param) |
Цитата:
Есть другое предложение по поводу использования статических локальных переменных. Код:
SqlStatement Database::CreateStatement(SqlStatementID& index, const char * fmt) Мысли, возражения? |
что-то тут не то с дизайном приложения ...
какой смысл инициализировать статическую переменную значением параметра передаваемую в функцию-член ? ведь по такой логике этот параметр будет игнорироваться во всех остальных случаях кроме первого раза. если я правильно понял идею то по моему это должно выглядеть примерно так: Код:
class Database; |
Цитата:
|
тут или я что-то не понимаю ... или в логике ошибка
если нужен кеш, то почему он должен быть один на все экземпляры класса ? кеш что кеширует ? данные экземпляра ? или все экземпляры содержат одинаковые данные ? если это действительно какой-то кеш который один на все возможные экземпляры класса, то он инициализируется 1 раз не из ран-тайма, а в компил-тайм, вроде того что я привел пример выше. В общем для меня слишком много непонятного, опишите ситуацию целиком если не трудно P.S. к тому же какой смысл объявлять глобальную переменную как статик ? глобальные переменные и так существуют в единственном экземпляре |
Йоха, мы инициализируем локальную статическую переменную функции, а не член класса :)
Код:
void Function() Поэтому не вижу причин для паники. |
Цитата:
если нужен перечень айди и еще какие-то параметры, почему бы не создать некий класс - менеджер этих данных и кэшировать их внутри нормальными способами, и не городить какие-то костыли с неопределенным поведением |
Йоха, менеджер уже сейчас есть и используется. Только вот постоянный поиск по хеш-таблице ради нужных даных по запросу - занятие довольно таки затратное, отчасти виной тому наши странные хеширующие функции для строк. При текущих 90 запросах мы имеем увеличение загрузки ЦП на 6-10%. А таких запросов при поддержке SELECTов будет порядка 150-200.
|
ну при таком подходе других вариантов нет, к тому же возможно затраты на поиск нужного prepared statement для строки запроса сведет на нет выигрыш от использования самих prepared statements. Тут придется только искать способ максимально быстро находить PS соответствующий sql выражению
|
Переделал патч, теперь траблов не должно быть с использованием статических локальных переменных. Объекты класса SqlStatementID теперь должны обеспечивать нужное нам поведение. Пробуйте.
|
DirectExecute() тысячи запросов с текстом, который нужно escape():
Код:
2854 ms Код:
671 ms |
Я планирую закоммитить патч в течение ближайшей недели в случае если не будут найдены проблемы в коде. На серверах с 1к+ онлайна ошибок на данный момент не обнаружено, поэтому можете начинать тестировать добровольно пока у вас есть время :)
|
Всем, кому интересна статистика с сервера MySQL, что обслуживает мангос с prepared statements, могут взглянуть на скриншот:
http://img705.imageshack.us/img705/3...statistics.png Доля PS теперь занимает 42% на сервере (поправьте если неправильно интерпретирую результаты). И это благодаря только 90 запросам из почти 900 в чистом ядре :) Цифра может отличаться от чистого мангоса, т.к. у тестировщика очень много сторонних патчей. fgenesis готовит патч, который позволит собрать статистику по каждому запросу к БД чтобы мы могли перевести на PS только критические для быстродействия запросы. |
Текущее время: 07:59. Часовой пояс GMT +3. |
ru-mangos.ru - Русское сообщество MaNGOS