[11284] Implement prepared statements for INSERT+DELETE+UPDATE SQL requests. Should improve player save performance + lower MySQL server CPU usage.

Note: PostgreSQL does not have prepared statements implemented using native APIs.

Huge thanks to Undergarun, kero99 and Vinolentus.

Signed-off-by: Ambal <pogrebniak@gala.net>
This commit is contained in:
Ambal 2011-03-25 21:52:59 +02:00
parent d9374d936f
commit 40ef9cbf2f
24 changed files with 1823 additions and 488 deletions

View file

@ -377,52 +377,65 @@ void Pet::SavePetToDB(PetSaveMode mode)
_SaveAuras();
uint32 ownerLow = GetOwnerGuid().GetCounter();
std::string name = m_name;
CharacterDatabase.escape_string(name);
// remove current data
CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND id = '%u'", ownerLow, m_charmInfo->GetPetNumber());
static SqlStatementID delPet ;
static SqlStatementID insPet ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delPet, "DELETE FROM character_pet WHERE owner = ? AND id = ?");
stmt.PExecute(ownerLow, m_charmInfo->GetPetNumber());
// prevent duplicate using slot (except PET_SAVE_NOT_IN_SLOT)
if (mode <= PET_SAVE_LAST_STABLE_SLOT)
CharacterDatabase.PExecute("UPDATE character_pet SET slot = '%u' WHERE owner = '%u' AND slot = '%u'",
PET_SAVE_NOT_IN_SLOT, ownerLow, uint32(mode) );
{
static SqlStatementID updPet ;
stmt = CharacterDatabase.CreateStatement(updPet, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?");
stmt.PExecute(uint32(PET_SAVE_NOT_IN_SLOT), ownerLow, uint32(mode));
}
// prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
if (getPetType()==HUNTER_PET && (mode==PET_SAVE_AS_CURRENT||mode > PET_SAVE_LAST_STABLE_SLOT))
CharacterDatabase.PExecute("DELETE FROM character_pet WHERE owner = '%u' AND (slot = '%u' OR slot > '%u')",
ownerLow, PET_SAVE_AS_CURRENT, PET_SAVE_LAST_STABLE_SLOT);
// save pet
std::ostringstream ss;
ss << "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) "
<< "VALUES ("
<< m_charmInfo->GetPetNumber() << ", "
<< GetEntry() << ", "
<< ownerLow << ", "
<< GetNativeDisplayId() << ", "
<< getLevel() << ", "
<< GetUInt32Value(UNIT_FIELD_PETEXPERIENCE) << ", "
<< uint32(m_charmInfo->GetReactState()) << ", "
<< uint32(mode) << ", '"
<< name.c_str() << "', "
<< uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1) << ", "
<< (curhealth < 1 ? 1 : curhealth) << ", "
<< curmana << ", "
<< GetPower(POWER_HAPPINESS) << ", '";
{
static SqlStatementID del ;
stmt = CharacterDatabase.CreateStatement(del, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)");
stmt.PExecute(ownerLow, uint32(PET_SAVE_AS_CURRENT), uint32(PET_SAVE_LAST_STABLE_SLOT));
}
// save pet
SqlStatement savePet = CharacterDatabase.CreateStatement(insPet, "INSERT INTO character_pet ( id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, "
"curmana, curhappiness, abdata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
savePet.addUInt32(m_charmInfo->GetPetNumber());
savePet.addUInt32(GetEntry());
savePet.addUInt32(ownerLow);
savePet.addUInt32(GetNativeDisplayId());
savePet.addUInt32(getLevel());
savePet.addUInt32(GetUInt32Value(UNIT_FIELD_PETEXPERIENCE));
savePet.addUInt32(uint32(m_charmInfo->GetReactState()));
savePet.addUInt32(uint32(mode));
savePet.addString(m_name);
savePet.addUInt32(uint32(HasByteFlag(UNIT_FIELD_BYTES_2, 2, UNIT_CAN_BE_RENAMED) ? 0 : 1));
savePet.addUInt32((curhealth < 1 ? 1 : curhealth));
savePet.addUInt32(curmana);
savePet.addUInt32(GetPower(POWER_HAPPINESS));
std::ostringstream ss;
for(uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i)
{
ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << " "
<< uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << " ";
};
savePet.addString(ss);
ss << "', "
<< time(NULL) << ", "
<< uint32(m_resetTalentsCost) << ", "
<< uint64(m_resetTalentsTime) << ", "
<< GetUInt32Value(UNIT_CREATED_BY_SPELL) << ", "
<< uint32(getPetType()) << ")";
savePet.addUInt64(uint64(time(NULL)));
savePet.addUInt32(uint32(m_resetTalentsCost));
savePet.addUInt64(uint64(m_resetTalentsTime));
savePet.addUInt32(GetUInt32Value(UNIT_CREATED_BY_SPELL));
savePet.addUInt32(uint32(getPetType()));
CharacterDatabase.Execute( ss.str().c_str() );
savePet.Execute();
CharacterDatabase.CommitTransaction();
}
// delete
@ -438,11 +451,26 @@ void Pet::DeleteFromDB(uint32 guidlow, bool separate_transaction)
if(separate_transaction)
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM character_pet WHERE id = '%u'", guidlow);
CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE id = '%u'", guidlow);
CharacterDatabase.PExecute("DELETE FROM pet_aura WHERE guid = '%u'", guidlow);
CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u'", guidlow);
CharacterDatabase.PExecute("DELETE FROM pet_spell_cooldown WHERE guid = '%u'", guidlow);
static SqlStatementID delPet ;
static SqlStatementID delDeclName ;
static SqlStatementID delAuras ;
static SqlStatementID delSpells ;
static SqlStatementID delSpellCD ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delPet, "DELETE FROM character_pet WHERE id = ?");
stmt.PExecute(guidlow);
stmt = CharacterDatabase.CreateStatement(delDeclName, "DELETE FROM character_pet_declinedname WHERE id = ?");
stmt.PExecute(guidlow);
stmt = CharacterDatabase.CreateStatement(delAuras, "DELETE FROM pet_aura WHERE guid = ?");
stmt.PExecute(guidlow);
stmt = CharacterDatabase.CreateStatement(delSpells, "DELETE FROM pet_spell WHERE guid = ?");
stmt.PExecute(guidlow);
stmt = CharacterDatabase.CreateStatement(delSpellCD, "DELETE FROM pet_spell_cooldown WHERE guid = ?");
stmt.PExecute(guidlow);
if(separate_transaction)
CharacterDatabase.CommitTransaction();
@ -1126,7 +1154,11 @@ void Pet::_LoadSpellCooldowns()
void Pet::_SaveSpellCooldowns()
{
CharacterDatabase.PExecute("DELETE FROM pet_spell_cooldown WHERE guid = '%u'", m_charmInfo->GetPetNumber());
static SqlStatementID delSpellCD ;
static SqlStatementID insSpellCD ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delSpellCD, "DELETE FROM pet_spell_cooldown WHERE guid = ?");
stmt.PExecute(m_charmInfo->GetPetNumber());
time_t curTime = time(NULL);
@ -1137,7 +1169,8 @@ void Pet::_SaveSpellCooldowns()
m_CreatureSpellCooldowns.erase(itr++);
else
{
CharacterDatabase.PExecute("INSERT INTO pet_spell_cooldown (guid,spell,time) VALUES ('%u', '%u', '" UI64FMTD "')", m_charmInfo->GetPetNumber(), itr->first, uint64(itr->second));
stmt = CharacterDatabase.CreateStatement(insSpellCD, "INSERT INTO pet_spell_cooldown (guid,spell,time) VALUES (?, ?, ?)");
stmt.PExecute(m_charmInfo->GetPetNumber(), itr->first, uint64(itr->second));
++itr;
}
}
@ -1163,6 +1196,9 @@ void Pet::_LoadSpells()
void Pet::_SaveSpells()
{
static SqlStatementID delSpell ;
static SqlStatementID insSpell ;
for (PetSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
{
++next;
@ -1174,15 +1210,26 @@ void Pet::_SaveSpells()
switch(itr->second.state)
{
case PETSPELL_REMOVED:
CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u' and spell = '%u'", m_charmInfo->GetPetNumber(), itr->first);
m_spells.erase(itr);
{
SqlStatement stmt = CharacterDatabase.CreateStatement(delSpell, "DELETE FROM pet_spell WHERE guid = ? and spell = ?");
stmt.PExecute(m_charmInfo->GetPetNumber(), itr->first);
m_spells.erase(itr);
}
continue;
case PETSPELL_CHANGED:
CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE guid = '%u' and spell = '%u'", m_charmInfo->GetPetNumber(), itr->first);
CharacterDatabase.PExecute("INSERT INTO pet_spell (guid,spell,active) VALUES ('%u', '%u', '%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second.active);
{
SqlStatement stmt = CharacterDatabase.CreateStatement(delSpell, "DELETE FROM pet_spell WHERE guid = ? and spell = ?");
stmt.PExecute(m_charmInfo->GetPetNumber(), itr->first);
stmt = CharacterDatabase.CreateStatement(insSpell, "INSERT INTO pet_spell (guid,spell,active) VALUES (?, ?, ?)");
stmt.PExecute(m_charmInfo->GetPetNumber(), itr->first, uint32(itr->second.active));
}
break;
case PETSPELL_NEW:
CharacterDatabase.PExecute("INSERT INTO pet_spell (guid,spell,active) VALUES ('%u', '%u', '%u')", m_charmInfo->GetPetNumber(), itr->first, itr->second.active);
{
SqlStatement stmt = CharacterDatabase.CreateStatement(insSpell, "INSERT INTO pet_spell (guid,spell,active) VALUES (?, ?, ?)");
stmt.PExecute(m_charmInfo->GetPetNumber(), itr->first, uint32(itr->second.active));
}
break;
case PETSPELL_UNCHANGED:
continue;
@ -1286,7 +1333,11 @@ void Pet::_LoadAuras(uint32 timediff)
void Pet::_SaveAuras()
{
CharacterDatabase.PExecute("DELETE FROM pet_aura WHERE guid = '%u'", m_charmInfo->GetPetNumber());
static SqlStatementID delAuras ;
static SqlStatementID insAuras ;
SqlStatement stmt = CharacterDatabase.CreateStatement(delAuras, "DELETE FROM pet_aura WHERE guid = ?");
stmt.PExecute(m_charmInfo->GetPetNumber());
SpellAuraHolderMap const& auraHolders = GetSpellAuraHolderMap();
@ -1340,14 +1391,28 @@ void Pet::_SaveAuras()
if (!effIndexMask)
continue;
stmt = CharacterDatabase.CreateStatement(insAuras, "INSERT INTO pet_aura (guid, caster_guid, item_guid, spell, stackcount, remaincharges, basepoints0, basepoints1, basepoints2, maxduration0, maxduration1, maxduration2, remaintime0, remaintime1, remaintime2, effIndexMask) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
CharacterDatabase.PExecute("INSERT INTO pet_aura (guid, caster_guid, item_guid, spell, stackcount, remaincharges, basepoints0, basepoints1, basepoints2, maxduration0, maxduration1, maxduration2, remaintime0, remaintime1, remaintime2, effIndexMask) VALUES "
"('%u', '" UI64FMTD "', '%u', '%u', '%u', '%u', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%i', '%u')",
m_charmInfo->GetPetNumber(), holder->GetCasterGuid().GetRawValue(), holder->GetCastItemGuid().GetCounter(), holder->GetId(), holder->GetStackAmount(), holder->GetAuraCharges(),
damage[EFFECT_INDEX_0], damage[EFFECT_INDEX_1], damage[EFFECT_INDEX_2],
maxduration[EFFECT_INDEX_0], maxduration[EFFECT_INDEX_1], maxduration[EFFECT_INDEX_2],
remaintime[EFFECT_INDEX_0], remaintime[EFFECT_INDEX_1], remaintime[EFFECT_INDEX_2],
effIndexMask);
stmt.addUInt32(m_charmInfo->GetPetNumber());
stmt.addUInt64(holder->GetCasterGuid().GetRawValue());
stmt.addUInt32(holder->GetCastItemGuid().GetCounter());
stmt.addUInt32(holder->GetId());
stmt.addUInt32(holder->GetStackAmount());
stmt.addUInt8(holder->GetAuraCharges());
for (int i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; ++i )
stmt.addInt32(damage[i]);
for (int i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; ++i )
stmt.addInt32(maxduration[i]);
for (int i = EFFECT_INDEX_0; i <= EFFECT_INDEX_2; ++i )
stmt.addInt32(remaintime[i]);
stmt.addUInt32(effIndexMask);
stmt.Execute();
}
}
}