discord py — низкая производительность при удалении сообщения (несколько серверов)

#python-3.x #discord.py #mysql-python

#python-3.x #discord.py #mysql-python

Вопрос:

У меня проблема. У меня есть глобальный чат, который обменивается сообщениями пользователей более чем на 100 серверах. Все сообщения имеют одноразовый код для удаления этого сообщения на каждом сервере.

Но моему боту требуется более 2 часов, чтобы удалить одно сообщение, которое действительно ужасно и плохо, если кто-то отправляет спам с оскорблением. Итак, я спрашиваю, как я могу ускорить свой код, чтобы он мог очень быстро удалить сообщение со всех серверов.

Мой код — это команда discord, которая удаляет определенные сообщения (каждое сообщение содержит одноразовый код и сохраняется в базе данных) на каждом сервере, на котором находится бот.

https://i.imgur.com/UAgVBCL.png Изображение того, как сообщения сохраняются в базе данных:
messageID = Исходный идентификатор сообщения от автора сообщения. code = одноразовый код для каждого сообщения. ids = все остальные идентификаторы сообщений, которые содержат один и тот же одноразовый код. time = удалите строку в это время, чтобы удалить очень старые сообщения из базы данных, чтобы прояснить ситуацию.

https://i.imgur.com/VfiIBCZ.png Изображение того, как моя таблица «серверы» сохраняется в БД:
guildID = guildid с конкретного сервера. channelID = канал, по которому бот публикует свои сообщения.

И это мой код для команды удаления сообщения:

 @bot.command(aliases=["delmsg", "deletemessage", "msgdelete", "del"])
    async def delete(ctx, code=None):
        guild = bot.get_guild(616655040614236160)
        member = guild.get_member(ctx.author.id)
        role2 = guild.get_role(792894127972155393)  # Admin
        role3 = guild.get_role(792894172829974529)  # Mod
     
        if role2 in member.roles or role3 in member.roles:
            mydb = mysql.connector.connect(
                host="**",
                user="**",
                password="**",
                database="global-bot"
            )
     
            mycursor = mydb.cursor()
     
            mycursor.execute(
                f"SELECT * FROM messeges WHERE code = '{code}'")
            myresult3 = mycursor.fetchall()
            if myresult3:
                await ctx.message.delete()
                await ctx.send('start deleting message..', delete_after=15)
                mycursor.execute(f"SELECT * FROM servers")  ##########
                myresult = mycursor.fetchall()
                ids = myresult3[0][2].split(" ")
                for x in ids:
                    for server in myresult:
                        try:
                            x1 = [server]
                            channel = bot.get_channel(int(x1[0][1]))
                            msg = await channel.fetch_message(int(x))
                            await msg.delete()
                        except:
                            pass
                for server in myresult:
                    try:
                        x1 = [server]
                        channel = bot.get_channel(int(x1[0][1]))
                        msg = await channel.fetch_message(myresult3[0][0])
                        await msg.delete()
                    except:
                        pass
                channel2 = bot.get_channel(794269462848077845)
                await ctx.send(f"message with code {code} was deleted", delete_after=15)
                await channel2.send(embed=embed2)
    
    
                sql = f"DELETE FROM messeges WHERE code = '{code}'" # This line here is to delete the row with the used code in the delete command, for let my bot regenerate it and use it in a different message sometime.
                mycursor.execute(sql)
                mydb.commit()
     
            else:
                await ctx.send(f"message with one-time code `{code}` could not be deleted! Maybe you had a typo or the code doesnt exist.", delete_after=15)
                await ctx.message.delete()
        else:
            await ctx.send("not enough rights")
 

Комментарии:

1. Проблема в том, что бот не может удалить его со всех быстрых серверов сервера? Или что он отстает и не удаляет первое сообщение через 2 часа

2. бот не может удалить его со всех быстрых серверов сервера.

3. Могли бы вы более подробно описать свое имя переменной? Например, что такое x и xx

4. отредактировал вопрос.

Ответ №1:

Посмотрев на ваш код некоторое время, я понял, что этот вложенный цикл здесь крайне неэффективен:

 for x in ids:
    for server in myresult:
        try:
           x1 = [server]
           channel = bot.get_channel(int(x1[0][1]))
           msg = await channel.fetch_message(int(x))
           await msg.delete()
         except:
           pass
 

Это связано с тем, что программа тратит огромное количество времени, пытаясь сопоставить идентификатор сообщения с правильным сервером. Вместо того, чтобы заставлять программу делать это, я настоятельно рекомендую вам сохранить внешний ключ в виде идентификатора гильдии с сообщением, когда оно будет отправлено вашим ботом и добавлено в базу данных.

Это позволит вам удалить вложенный цикл и выполнять цикл только по идентификатору сообщения, поскольку у вас уже будет соответствующий идентификатор гильдии для каждого сообщения.

Комментарии:

1. Как это будет выглядеть? Я в замешательстве you store a foreign key in the form of the guild's id with a message when it's posted by your bot and added to the db. .

2. Вот как я сохраняю сообщения в своей таблице: pastebin.com/v6LNEf1W

3. w3schools.com/sql/sql_foreignkey.asp <- Руководство по внешним ключам. Я подразумеваю, что в вашей базе данных сообщений должен быть дополнительный столбец, содержащий идентификатор гильдии, соответствующий этому сообщению.

4. Итак, я должен добавить guildID в таблицу базы данных сообщений в виде столбца? А потом?

5. а затем вы включаете это в свой код. Таким образом, вместо того, чтобы тратить много времени на попытки сопоставить идентификатор сообщения с правильным сервером, вы можете просто перебирать каждое сообщение, используя guildid из базы данных, чтобы удалить сообщение из этой конкретной гильдии. Это удаляет вложенный цикл.