1. Соблюдайте Правила форума и проявляйте уважение к другим участникам беседы.

Оптимизация insert select запросов бота в БД.

Тема в разделе 'Кодинг/Собственные решения', создана пользователем Mefix, 6 дек 2011.

Статус темы:
Закрыта.
  1. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    ViperNight:
    Ну примерно я это и буду делать, но чтобы не плодить доп поля записей я буду сносить в существующую таблицу Score.
    Пример запроса как происходит суммирование, можно привести? Как понимаю просто сыгралась игра, данные которой записали стандартом в dotaPlayers, и ещё эти же данные заплюсовались, если значения уже есть, или новая запись если значений нет? И вот думаю, может стоит таблицу DotaPlayer тоже занести поле Name? Или просчёт быстрее по ID идёт?


    ROB, как объяснил человек выше, это меняет многое, и эксперимент уже был поставлен, и как видимо удачно. Почитал ещё скрипты бота, так и не нашёл обозначения таблицы из которой берётся значение. Но From *, походу означает что выборка идёт по всей базе где имя = такому то. Пошёл биться апстену. в ghost++ оригинальном вроде такого дебилизма нет, или просто плохо искал.
  2. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Код:
    	Query = "select totgames,wins,losses,killstotal,deathstotal,creepkillstotal,creepdeniestotal,assiststotal,neutralkillstotal,towerkillstotal,raxkillstotal,courierkillstotal, server from(SELECT total_games as totgame,total_wins as killstotal, total_deatsh as deathtotal, total_assists as assisttotals, total_creepKills as creepkillstotal, total_CreepDenies as creepdeniestotal, total_neutralKills as neutralkillstotal, total_courierKills as courierkillstotal, total_towerKills as towerkillstotal, total_raxKills as raxkillstotal, total_courierKills as courierkillstotal FROM totalstats, WHERE name = '"+name+"') as i;
    	if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 )
    		*error = mysql_error( (MYSQL *)conn );
    	else
    	{
    		MYSQL_RES *Result = mysql_store_result( (MYSQL *)conn );
    
    		if( Result )
    		{
    			vector<string> Row = MySQLFetchRow( Result );
    
    			//if( Row.size( ) == 22 )
    			if( Row.size( ) == 13 )
    			{
    				uint32_t TotalGames = UTIL_ToUInt32( Row[0] );
    
    				if( TotalGames > 0 )
    				{
    					uint32_t TotalWins = UTIL_ToUInt32( Row[1] );
    					uint32_t TotalLosses = UTIL_ToUInt32( Row[2] );
    					uint32_t TotalKills = UTIL_ToUInt32( Row[3] );
    					uint32_t TotalDeaths = UTIL_ToUInt32( Row[4] );
    					uint32_t TotalCreepKills = UTIL_ToUInt32( Row[5] );
    					uint32_t TotalCreepDenies = UTIL_ToUInt32( Row[6] );
    					uint32_t TotalAssists = UTIL_ToUInt32( Row[7] );
    					uint32_t TotalNeutralKills = UTIL_ToUInt32( Row[8] );
    					uint32_t TotalTowerKills = UTIL_ToUInt32( Row[9] );
    					uint32_t TotalRaxKills = UTIL_ToUInt32( Row[10] );
    					uint32_t TotalCourierKills = UTIL_ToUInt32( Row[11] );
    
    
    ммм???? Это запрос статистики. Только в изначальном варианте есть gamestate - это что такое?
  3. ViperNight ▒▒▒▒▒▒▒▒▒

    Сообщения:
    311
    Спасибы:
    154
    Сборка бота GHost:
    GHost++ r597M
    Дата начала использования бота:
    20.01.2007
    Skype:
    Мой статус
    gamestate - показывает, к какому типу относилась игра, 16 - публичная, 17 - приватная.
  4. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    а 231?
    Использую brtGhost
    Что-то не догоняю, в боте можно запросить статистику за одну игру? Или только статистику по приватным играм?
    Если нет и эта обвязка не прописана, то как понимаю строчку if Query = ****** group* ga.gamestate = '"+gamestate+"', можно удалить(закоментить)?
    Или в боте сделано так что статистика запрашивается только по паб играм, или по приватным играм?
    Ну это дело десятое, если уж оптимизировать и полностью, то скорее всего можно будет такую же таблицу сделать для приватных игр, и стата по приватным и публичным играм может вестись отдельно, а если общий запрос за все игры, то просто суммировать данные с одной таблицы с данными из другой.

    PS: Ну я тут в хапросе немного накосячил, с обозначением, что есть что, и одно обозначение забыл, позже поправлю.
    I_aM_Fake нравится это.
  5. ____ROB____ Старожила

    Сообщения:
    1.008
    Спасибы:
    22
    Сборка бота GHost:
    Ghost One 1.5
    да :spy:
  6. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Код:
    string Query = "SELECT total_games,total_wins, total_losses, total_kills, total_deaths, total_creepKills, total_CreepDenies, total_assists, total_neutralKills, total_towerKills, total_raxKills, total_courierKills, server FROM totalstats WHERE name = '"+name+"'";
    
    			if( mysql_real_query( (MYSQL *)conn, Query.c_str( ), Query.size( ) ) != 0 )
    		*error = mysql_error( (MYSQL *)conn );
    	else
    	{
    		MYSQL_RES *Result = mysql_store_result( (MYSQL *)conn );
    
    		if( Result )
    		{
    			vector<string> Row = MySQLFetchRow( Result );
    
    				if( Row.size( ) == 13 )
    				{
    				uint32_t TotalGames = UTIL_ToUInt32( Row[0] );
    
    				if( TotalGames > 0 )
    				{
    					uint32_t TotalWins = UTIL_ToUInt32( Row[1] );
    					uint32_t TotalLosses = UTIL_ToUInt32( Row[2] );
    					uint32_t TotalKills = UTIL_ToUInt32( Row[3] );
    					uint32_t TotalDeaths = UTIL_ToUInt32( Row[4] );
    					uint32_t TotalCreepKills = UTIL_ToUInt32( Row[5] );
    					uint32_t TotalCreepDenies = UTIL_ToUInt32( Row[6] );
    					uint32_t TotalAssists = UTIL_ToUInt32( Row[7] );
    					uint32_t TotalNeutralKills = UTIL_ToUInt32( Row[8] );
    					uint32_t TotalTowerKills = UTIL_ToUInt32( Row[9] );
    					uint32_t TotalRaxKills = UTIL_ToUInt32( Row[10] );
    					uint32_t TotalCourierKills = UTIL_ToUInt32( Row[11] );
    
    
    
    					double wpg = 0;
    					double lpg = 0;
    					double kpg = (double)TotalKills/TotalGames;
    					double dpg = (double)TotalDeaths/TotalGames;
    					double ckpg = (double)TotalCreepKills/TotalGames;
    					double cdpg = (double)TotalCreepDenies/TotalGames;
    					double apg = (double)TotalAssists/TotalGames;
    					double nkpg = (double)TotalNeutralKills/TotalGames;
    					double tkpg = (double)TotalTowerKills/TotalGames;
    					double rkpg = (double)TotalRaxKills/TotalGames;
    					double coukpg = (double)TotalCourierKills/TotalGames;
    					server = Row[12];
    					uint32_t Rank = 0;
    					wpg = (double)TotalWins/TotalGames;
    					lpg = (double)TotalLosses/TotalGames;
    					wpg = wpg * 100;
    					lpg = lpg * 100;
    					uint32_t leavecount = 0;
    Частично работает. Выдало все заполненные поля по !sd и !statsdota. Кроме ливов(дисконов)
    Немогу найти где эти данные находятся. Чтобы переписать на запрос из другой таблицы.
  7. Deals Старожила

    Сообщения:
    784
    Спасибы:
    21
    Сборка бота GHost:
    Ghost One 1.7.266
    Skype:
    Мой статус
    Mefix привел отличный пример.
    Его можно брать за основу.
    Но есть одно НО!
    Код:
    WHERE name = '"+name+"'";
    Не забывайте что GHost это мульти игровой и мульти бнетовский клиент.
    Соответственно нужно имя игрока и сервера с которого он играет.
    Например человек с ником Deals (например я) на Алькаре будет совсем другой на iCCup'е (какой-то Вася).
    И все. Статистика ложная. Так же не забывайте про botid. Который, кстати, почти нигде не работает. Его тоже можно пофиксить.
  8. Deals Старожила

    Сообщения:
    784
    Спасибы:
    21
    Сборка бота GHost:
    Ghost One 1.7.266
    Skype:
    Мой статус
    Ну и как описывалось выше, значения в поля total**** таблицу добавлять по окончании игры. И сразу их частично обрабатывать. Так же и забирать из из таблицы частично обрабатывая.
  9. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Ну я сперва хочу довести до ума значения, значит надо ещё Where name = *, server=*,
    То есть ещё надо будет ввести чтобы смотрела откуда чел зашёл и т.д. Но как я посмотрел раньше хоть и писалось на каком сервере игрок играл, но по СД вроде этого не отображалось. В запросах старых запросах вроде только gamestate фигурировал. Ну или я плохо прочитал... Слишком много текста, так сказать "ниасилил" ))).

    А про LeaveCount? как оно определяется? Я никак понять не могу. Мне кажется что видимо по разнице конца игры в которой играл человек, и времени его выхода. И если оно меньше значения проставленного в конфиге(за сколько мин банить), то ему приписываются ливы.

    PS: botid = Вот для чего он нужен? Если честно, так и не понял.
  10. Deals Старожила

    Сообщения:
    784
    Спасибы:
    21
    Сборка бота GHost:
    Ghost One 1.7.266
    Skype:
    Мой статус
    botid - идентификация ботов.
    Не забывай что база данных может использоваться не 1 ботом. 1 бот для доты 6.60 версии, 2 бот для 6.70 версии и т.д.
    И теперь если сравнивать как бы логично и статы должны бить для каждого бота свои. Для этого и есть botid в конфиге бота и в базе данных botid как показатель с каким ботом идет речь.
    В общем чтоб статы ботов не путались. Или если ты хочешь чтоб стата была общая но ботов несколько - просто ставишь одинаковый botid и получится что будет идти в 1 статистику.
  11. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Ясно... Ну я думаю что как бы botid сейчас не сильно актуально. Ибо ведём для одну статистику, на версию карты как то по барабану. Ибо если обновляем так у всех сразу.

    ЗЫ: Перецитирую:
  12. Deals Старожила

    Сообщения:
    784
    Спасибы:
    21
    Сборка бота GHost:
    Ghost One 1.7.266
    Skype:
    Мой статус
    Ну Leavecount, по-моему, полностью сделан только в brt. Смотри там как он работает!
  13. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Вот не могу понять как он работает ((( Ладно на досуге ещё покопаю )

    ЗЫ: Ппц.... Нашёл все значения... В итоге попал в цикл. Не понятно как высчитывается кол-во ливов (
  14. rost Гуру

    Сообщения:
    1.258
    Спасибы:
    150
    Сборка бота GHost:
    LtG
    Дата начала использования бота:
    01.11.2010
    Skype:
    Мой статус
    Да можно проще както зделать.
    Неговорю о выводе его в стату !sd, но в подсчет ОЧКОВ легко.
    Зделай чтото типа leftreason при ливе leave
    Потом в ghostdbmysql.cpp найди
    Код:
    bool MySQLCalculateScores
    засунь наверное туда это
    SUM(gp.leftreason LIKE 'leave') as leave
    Ну и в формулу сунь и делай че надо, у меня leave*100

    =====
    ну было так, когда считал бот)
  15. Mefix Наш человек

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

    А так я сейчас и собираюсь сделать чтобы лефт резон в отдельную таблицу засчитывался и плюсовался. Но нельзя делать 2 разных лефта, нужно найти другой сперва.
  16. rost Гуру

    Сообщения:
    1.258
    Спасибы:
    150
    Сборка бота GHost:
    LtG
    Дата начала использования бота:
    01.11.2010
    Skype:
    Мой статус
    Когда я делал, руские несчитало!!!
    Потому я и зделал для лива себе ризон ban
    Может я что-то не так делал, критику слушать по этому нехочу поводу, т.к. неотвечу на нее.
    Но пытался что-то зделать с руским ризоном - неполучилось - забил х*й.
    Работает и щас норм че.
  17. fake Старожила

    Сообщения:
    1.624
    Спасибы:
    19
    Дата начала использования бота:
    11.11.11
    в опен стат по разнице времени, в моем боте все проще, находит плеер дисконектед в statsdota.cpp и добовляет в бд
  18. rost Гуру

    Сообщения:
    1.258
    Спасибы:
    150
    Сборка бота GHost:
    LtG
    Дата начала использования бота:
    01.11.2010
    Skype:
    Мой статус
    Ну можно и по лефт ризону, это тоже практично довольно.
    Просто что нельзя зделать типа откат 3 минуты на лив и тд... но мне ненужно у меня пермамент бан после 1 секи
  19. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Выцепил запрос.
    Код:
    SELECT count(*) FROM gameplayers as gp LEFT JOIN games ON games.id=gp.gameid WHERE gp.left < games.duration - 180 AND gp.name='mefix';
    В коде:

    Хм... То есть переписываем так: ничего не сравниваем, а берём просто из таблицы.

    Но остаётся вопрос тогда, как правильно потом добавлять лив в нужное поле таблицы?
    Так, у нас же все игры как данные о сыгранной игре, и игре игрока добавляются в БД только после окончания? Не важно ливнул человек сразу или позже?
    Тогда как я думаю, когда заканчивается игра, нужно просто сравнить ID игры и человека, и если время лива и окончания игры меньше 180 секунд, то заносим в БД, то что лив, но это надо делать с таймаутом чтобы данные об игре и человеке уже были в БД. Но что-то мне не нравится это лишние увеличение нагрузок на запросы в БД. Возможно лучше стоит дописать, если по окончанию игры(время же когда он ливнул всёравно же в буфере уже хранится?), то есть время под конец игры тоже есть в буфере, в итоге на основании этого можно написать, если время left < duration - 180(а лучше воткнуть переменную из конфига), когда name="+name+", тогда добавляем +1 в таблицу totalstats где name="+name", иначе ничего не делаем.

    Ну или как говорили по лефт ризону. По сути в БД заносится лефт резон из файла language, в итоге я думаю можно поставить сравнение, если leftreson = lang* or lang* or lang*, тогда лив и заносим в БД, иначе ничего.
    Сейчас основываюсь на том, что сравнение будет происходит по выдаваемому значению lang, в боте же оно хранится всё в одной кодировке, и перед внесением в БД о причине покидания игры он же вызывается, и после вызова нужного lang просто делать сравнение, или в каждом месте где lang вызывается дописать, что при таких-то в БД занести данные что лив, а при других просто не писать.

    Ммм.. Какая теория имеет право жить? И какую лучше в зачатке уничтожить?
  20. Mefix Наш человек

    Сообщения:
    114
    Спасибы:
    3
    Тут мимолётом решил посмотреть почему OpenStats глючит. После 5-ти минут просмотра тормозящих запросов понял.
    Странно что тут в общеобсуждаемых темах этого никто не сказал.
    Т.к. в нескольких таблицах, при падениях ботов могут записаться не все значения(или если БД упала). Соответственно ID игр разные. Соответственно чтобы работала нормально стата, нужно несколько таблиц совмещать в одну. И переписывать все SQL запросы в боте и в DotaOpenstats... В общем у мну трагедия по этому поводу. Или как-то свойствами Mysql пропускать запрос на выборку значения, если в БД нет нужного поля.
Статус темы:
Закрыта.