Question

J'ai une table de base de données dans laquelle chaque ligne a une clé primaire générée aléatoirement, un message et un utilisateur. Chaque utilisateur a environ 10 à 100 messages, mais il y a entre 10 000 et 50 000 utilisateurs.

J'écris les messages quotidiennement pour chaque utilisateur en une fois. Je veux jeter les anciens messages de chaque utilisateur avant d'écrire les nouveaux pour que la table soit aussi petite que possible.

En ce moment, je le fais effectivement:

delete from table where user='mk'

Ensuite, écrivez tous les messages pour cet utilisateur. Je vois beaucoup de différends parce que j'ai beaucoup de fils qui le font en même temps.

Je dois également conserver l'ensemble de messages le plus récent pour chaque utilisateur.

Je n'ai pas directement accès à la base de données. J'essaie de deviner le problème sur la base de commentaires de seconde main. La raison pour laquelle je me concentre sur ce scénario est que la requête de suppression indique beaucoup de temps d'attente (encore une fois - à ma connaissance), en plus d'une fonctionnalité récemment ajoutée.

Quelqu'un peut-il donner un conseil?

Serait-il préférable de:

select key from table where user='mk'

Ensuite, supprimez des lignes individuelles à partir de là? Je pense que cela pourrait conduire à un verrouillage moins brutal.

Était-ce utile?

La solution

Non, il est toujours préférable d'exécuter une seule instruction SQL sur un ensemble de lignes plutôt qu'une série de "phrases par lignes". (ou ce que Tom Kyte appelle des opérations "lentes par lentes"). Quand vous dites que vous "voyez beaucoup de querelles", qu'est-ce que vous voyez exactement? Une question évidente: la colonne USER est-elle indexée?

(Bien entendu, le nom de la colonne ne peut pas vraiment être USER dans une base de données Oracle, car il s'agit d'un mot réservé!)

MODIFIER: vous avez indiqué que la colonne USER n'était pas indexée. Cela signifie que chaque suppression impliquera une analyse complète de la table allant jusqu'à 50 000 * 100 = 5 millions de lignes (ou au mieux 10 000 * 10 000 lignes) pour supprimer de 10 à 100 lignes. Ajouter un index sur USER peut résoudre vos problèmes.

Autres conseils

Si vous faites cela tous les jours pour chaque utilisateur, pourquoi ne pas simplement supprimer tous les enregistrements de la table en une seule instruction? Ou même

truncate table whatever reuse storage
/

modifier

La raison pour laquelle je suggère cette approche est que le processus ressemble à un téléchargement quotidien par lot de messages utilisateur, précédé de la suppression des anciens messages. C'est-à-dire que les règles de gestion me semblent être les suivantes: "la table ne contiendra qu'une journée de messages pour un utilisateur donné". Si ce processus est effectué pour chaque utilisateur, une seule opération serait la plus efficace.

Toutefois, si les utilisateurs ne reçoivent pas chaque jour un nouvel ensemble de messages et , il existe une règle subsidiaire selon laquelle nous devons conserver l'ensemble de messages le plus récent pour chaque utilisateur. se tromper.

Êtes-vous sûr de voir un conflit de verrous? Il semble plus probable que vous constatiez des conflits de disque en raison d'un trop grand nombre de mises à jour simultanées (mais non liées). La solution à cela consiste simplement à réduire le nombre de threads que vous utilisez: Moins de conflits de disque signifie un débit total plus élevé.

Je pense que vous devez définir vos exigences un peu plus clairement ...

Par exemple. Si vous connaissez tous les utilisateurs pour lesquels vous souhaitez écrire des messages, insérez les ID dans une table temporaire, indexez-la sur ID et supprimez-la par lots. Ensuite, les discussions que vous lancez font deux choses. Écrivez l'ID de l'utilisateur dans une table temporaire, écrivez le message dans une autre table temporaire. Ensuite, lorsque les threads ont fini de s’exécuter, le thread principal doit

DELETE * FROM Messages INNER JOIN TEMP_MEMBERS ON ID = TEMP_ID

INSERT INTO MESSAGES SELECT * FROM TEMP_messges

Je ne suis pas familier avec la syntaxe Oracle, mais c’est de cette façon que je l’aborderais SI les messages des utilisateurs sont tous envoyés en succession rapide.

J'espère que cela vous aidera

Parlez à votre administrateur de base de données

Il est là pour vous aider. Lorsque nous, les administrateurs de base de données, retirons l’accès des développeurs pour une opération de ce type, nous supposons que nous vous fournirons une assistance. Si votre code prend trop de temps à terminer et que ce temps semble être pris dans la base de données, votre administrateur de base de données sera en mesure d'examiner exactement ce qui se passe et de proposer des suggestions, voire même de résoudre le problème sans que vous ne changiez quoi que ce soit.

En parcourant votre énoncé de problème, il ne semble pas que vous examiniez des problèmes de conflit, mais je ne connais rien à votre structure sous-jacente.

Vraiment, parlez à votre administrateur de base de données. Il aura probablement plaisir à regarder quelque chose d’amusant au lieu de planifier le dernier déploiement de la CPU.

Cela pourrait accélérer les choses:

Créer une table de recherche:

create table rowid_table (row_id ROWID ,user VARCHAR2(100));
create index rowid_table_ix1 on rowid_table (user);

Exécuter un travail de nuit:

truncate table rowid_table;
insert /*+ append */ into rowid_table
select ROWID row_id , user
from table;
dbms_stats.gather_table_stats('SCHEMAOWNER','ROWID_TABLE');

Ensuite, lors de la suppression des enregistrements:

delete from table
where ROWID IN (select row_id
                from rowid_table
                where user = 'mk');

Votre propre suggestion semble très judicieuse. Le verrouillage en petites quantités présente deux avantages:

  • les transactions seront plus petites
  • le verrouillage sera limité à quelques lignes à la fois

Le verrouillage en lots devrait constituer une grande amélioration.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top