javamysql更新优化

javamysql更新优化,java,mysql,Java,Mysql,我有一个将播放器数据从一个条目上传到MySQL数据库的代码。查询如下所示: uploadPlayers = getManager().getMysqlManager().getConnection().prepareStatement("UPDATE players SET name=?, ips=?, gamemode=?, lastlogin=?, timeplayed=?, rank=?, badges=?, level=? WHERE uuid=?");

我有一个将播放器数据从一个条目上传到MySQL数据库的代码。查询如下所示:

            uploadPlayers = getManager().getMysqlManager().getConnection().prepareStatement("UPDATE players SET name=?, ips=?, gamemode=?, lastlogin=?, timeplayed=?, rank=?, badges=?, level=? WHERE uuid=?");
    @Override
public void saveDataToDatabase() {
    try{
        for (final Entry<String, IPlayerData> entry : playerdatalist.entrySet()) {
            final IPlayerData pd = entry.getValue();

            SH.uploadPlayers.setString(1, pd.getName());
            SH.uploadPlayers.setString(2, pd.getIp());
            SH.uploadPlayers.setInt(3, pd.getGamemode());
            SH.uploadPlayers.setString(4, SH.getManager().getMysqlManager().getDate(pd.getLastlogin()));
            SH.uploadPlayers.setLong(5, pd.getTimeplayed());
            SH.uploadPlayers.setInt(6, pd.getRank());
            SH.uploadPlayers.setString(7, pd.getBadgesAsString());
            SH.uploadPlayers.setInt(8, pd.getLevel());
            SH.uploadPlayers.setString(9, pd.getUUID());
            SH.uploadPlayers.addBatch();


        }   
        SH.uploadPlayers.executeBatch();
    }catch(SQLException e){
        e.printStackTrace();
    }
上传播放器的方法如下所示:

            uploadPlayers = getManager().getMysqlManager().getConnection().prepareStatement("UPDATE players SET name=?, ips=?, gamemode=?, lastlogin=?, timeplayed=?, rank=?, badges=?, level=? WHERE uuid=?");
    @Override
public void saveDataToDatabase() {
    try{
        for (final Entry<String, IPlayerData> entry : playerdatalist.entrySet()) {
            final IPlayerData pd = entry.getValue();

            SH.uploadPlayers.setString(1, pd.getName());
            SH.uploadPlayers.setString(2, pd.getIp());
            SH.uploadPlayers.setInt(3, pd.getGamemode());
            SH.uploadPlayers.setString(4, SH.getManager().getMysqlManager().getDate(pd.getLastlogin()));
            SH.uploadPlayers.setLong(5, pd.getTimeplayed());
            SH.uploadPlayers.setInt(6, pd.getRank());
            SH.uploadPlayers.setString(7, pd.getBadgesAsString());
            SH.uploadPlayers.setInt(8, pd.getLevel());
            SH.uploadPlayers.setString(9, pd.getUUID());
            SH.uploadPlayers.addBatch();


        }   
        SH.uploadPlayers.executeBatch();
    }catch(SQLException e){
        e.printStackTrace();
    }
@覆盖
public void saveDataToDatabase(){
试一试{
for(最终条目:playerdatalist.entrySet()){
final IPlayerData pd=entry.getValue();
setString(1,pd.getName());
setString(2,pd.getIp());
setInt(3,pd.getGamemode());
setString(4,SH.getManager().getMysqlManager().getDate(pd.getLastlogin());
setLong(5,pd.getTimeplayed());
setInt(6,pd.getRank());
setString(7,pd.getBadgesString());
setInt(8,pd.getLevel());
setString(9,pd.getUUID());
SH.uploadPlayers.addBatch();
}   
SH.uploadPlayers.executeBatch();
}捕获(SQLE异常){
e、 printStackTrace();
}
条目和数据库中大约有1500名玩家。 但每次我使用代码时,都要用15-20秒来更新所有玩家。
如何使其运行更快并进行优化?

您需要在
uuid
列上创建一个索引

如果没有索引,对于批处理中的每个条目,DB引擎将必须遍历表中的所有行,以确定要更新的行,从而使您的时间复杂度达到(更新的行数)*(表中的所有行数)。有了索引,时间复杂度将下降到仅更新的行数


添加索引会给更新和插入带来额外的(时间)成本,但是如果您总是通过行的
uuid
(您可能是这样)更新行,那么与改进相比,这将是微不足道的。

这里有两个问题。正如@JiriTousek所建议的,在uuid字段上没有索引会降低您的速度(+1表示该答案)。第二个问题是您正在更新所有字段,是否严格需要这些字段

根据报告:

update语句就像使用 写入的额外开销。写入速度取决于 正在更新的数据量和正在更新的索引数 已更新。未更改的索引不会更新

UUID字段是charfield,长度为9个字符,这一事实意味着这里的索引将起到很大的推动作用。即使是部分索引也可能起作用

报告还说:

如果将列设置为当前的值,MySQL会注意到这一点 并且不更新它

尽管如此,您不应该更新所有字段(如果它们不是严格需要的话),因为您来回传递了大量数据,绑定参数的开销也非常小


最后,如果速度真的很重要@GordonLinoff建议创建一个临时表,然后用一条语句进行更新。如果你发现速度很慢@GordonLinoff,那么加载数据填充的其他建议是最好的选择。

将数据上传到一个临时表中。然后执行一次
更新使用
join
进行操作。如果数据不在数据库中,则
load data infle
是一种快速获取数据的方法。您在
uuid
列上有索引吗?没有,我在uuid列上没有索引,但这不只是有助于选择吗?正如@JiriTousek所说的,索引确实有助于更新(查找要更新的行的速度要快得多,这通常超过了保持索引更新的成本)。使用JDK中的JVisualVM或使用netbeanas/eclipse并分析您的代码。连接可能在自动提交上,但您使用的是addBatch/executeBatch。我个人使用executeUpdate,自己处理批处理,然后在添加索引还不够时提交一个好提示。不过,实现起来更困难,所以我只会在添加索引时速度仍然较慢时才考虑它索引,或者如果Java和DB之间发送的数据量值得关注,那么这种开销只会增加每个更新行的固定时间,而不是与表大小成线性关系。