2017-09-15 4 views
0

J'ai une base de données mysql (en fait MariaDB 5.5.52) décrit à peu près comme suit:Comment commander un index composite pour éviter les blocages d'insertion?

CREATE TABLE table1 (
    id INT NOT NULL AUTOINCREMENT, 
    col1 INT, 
    col2 VARCHAR(32), 
    col3 VARCAHR(128), 
    PRIMARY KEY (ID), 
    UNIQUE KEY index1 (col1, col2, col3) 
); 

Il y a plus de colonnes, mais tous sont à l'intérieur de la clé UNIQUE, et il n'y a pas d'autres clés de la table.

Je cours plusieurs threads d'un script python qui insère dans cette base de données. Chaque thread fait autour 100-1000 inserts en utilisant mysql.connector de executemany tels que

ins_string = "INSERT IGNORE INTO table1 ({0}) VALUES ({1});" 
cursor.executemany(ins_string.format(fields, string_symbols), values) 

Je rencontre des problèmes de blocage constants. Je suppose que ces problèmes sont causés parce que chaque thread verrouille entre les lignes de table1 dans un ordre semi-aléatoire basé sur l'ordre dans lequel ma liste python values est générée. Ceci est en quelque sorte validé par des tests; Lorsque je crée une nouvelle base de données à partir de zéro avec 24 threads, le taux d'interblocage par instruction executemany() est> 80%, mais au moment où il y a un million + lignes dans la base de données, le taux de blocage est proche de zéro.

J'avais envisagé la possibilité que le blocage est le résultat de threads en compétition pour AUTOINCREMENT, mais dans le mode de verrouillage InnoDB 'consécutif' par défaut, cela ne semble pas être le cas. Chaque thread est supposé obtenir un table level lock jusqu'à la fin de l'INSERT. Cependant, la façon dont les verrous d'AUTOINCREMENT et INSERT interagissent m'embrouille, donc si je me trompe, faites le moi savoir.

Donc, si le problème est causé par l'ordre aléatoire de la clé unique, j'ai besoin d'un moyen de trier les instructions d'insertion dans python avant de les passer à MySQL. L'index est haché d'une certaine façon par MySQL, puis commandé. Comment je peux répliquer le hachage/commande en python?

Je demande une solution à mon diagnostic du problème ici, mais si vous voyez que mon diagnostic est faux, encore une fois, s'il vous plaît faites le moi savoir.

Répondre

0

Pourquoi avoir ID, puisque vous avez une clé UNIQUE qui pourrait être promu à PRIMARY? Quoiqu'il en soit, trier les lignes d'insertion en bloc sur (col1, col2, col3) avant de créer le executemany. Si cela ne suffit pas, diminuez le nombre de lignes dans chaque executemany. 100 rangs se situent à environ 10% du maximum théorique. Si 100 diminue la fréquence des interblocages ci-dessous, disons 10%, alors vous êtes probablement très près de l'équilibre optimal entre la vitesse de chargement en masse et le ralentissement dû à la relecture des impasses.

Combien de cœurs de processeur avez-vous?

Y a-t-il d'autres index que vous ne nous montrez pas? ChaqueUNIQUE facteurs d'index dans ce problème. Les index non uniques ne sont pas un problème. S'il vous plaît fournir le plein SHOW CREATE TABLE.

+0

Il y a huit colonnes, toutes dans l'index UNIQUE; sinon c'est l'instruction 'CREATE TABLE' complète. La colonne 'id' existe pour être la clé étrangère pour une variété de sous-tables. Je n'ai jamais plus de threads que de processeurs, en général je suis sur des serveurs à 48 cœurs tout en limitant à 24 threads ou moins (il y a d'autres processus en cours). – kingledion

+0

@kingledion - OK; ces réponses semblent raisonnables. Donc, je vote pour (1) pré-trier les lignes pour l'exécution et (2) de plus petits lots.Moins de 24 threads pourraient aider à éviter les blocages, mais faire moins de travail - ne peut pas prédire si cela en vaut la peine. Quelle version de MySQL? Les anciennes versions étaient inefficaces à 24 threads. –

+0

C'est MariaDB 5.5.52. Je suppose que je devrais mentionner que c'est MariaDB ... Qu'est-ce qui constitue une «vieille» version? – kingledion