2010-09-18 9 views
3

J'ai essayé d'effectuer une jointure sur deux tables dans MySQL, et la requête sera exécutée pendant une minute ou deux avant de manquer de mémoire sans obtenir des résultats. Je suis loin d'être un expert en base de données, donc je ne sais pas si j'écris mal mes requêtes, si j'ai des paramètres MySQL mal configurés, ou si je devrais vraiment faire autre chose avec ma requête. Pour info, la base de données est située localement sur ma machine.MySQL Une mauvaise performance Rejoignez

J'ai une grande table (~ 2 millions d'enregistrements) où l'une des colonnes est un ID dans une petite table (~ 3000 dossiers). Dans le cas où cela est important, l'ID n'est pas unique dans la grande table mais est unique dans la petite table. J'ai essayé différentes saveurs de la requête suivante, mais rien ne semble fonctionner:

SELECT big_table.*, 
     small_table.col 
    FROM big_table 
left outer join small_table on (big_table.small_id = small_table.id) 

Je fais beaucoup d'analyse sur les données qui nécessite les 2 millions de lignes, mais pas nécessairement en une seule question. Voici les résultats de mon « show create table »:

'big_table', 'CREATE TABLE 'big_table' (
    'BIG_ID_1', varchar(12) NOT NULL, 
    'BIG_ID_2', int(100) NOT NULL, 
    'SMALL_ID' varchar(8) DEFAULT NULL, 
    'TYPICAL_OTHER_COLUMN' varchar(3) DEFAULT NULL, 
    ... 
    PRIMARY KEY ('BIG_ID_1', 'BIG_ID_2') 
) ENGINE=MyISAM DEFAULT CHARSET=latin1' 

'small_table', 'CREATE TABLE `small_table` (
    `id`, varchar(8) NOT NULL DEFAULT '''', 
    `col`, varchar(1) DEFAULT NULL, 
    ... 
    PRIMARY KEY (`id`), 
    KEY `inx_id` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1' 

Voici le résultat « expliquer » pour un de mes requêtes candidats:

 
id select_type table  type possible_keys key  key_len ref       rows  extra 
1 SIMPLE  big_table ALL  NULL   NULL  NULL  NULL      1962193  
1 SIMPLE  small_table eq_ref PRIMARY,inx_id PRIMARY 10  db_name.big_table.SMALL_ID 1   
+0

Et quels indices avez-vous? Si vous n'en dites aucun, c'est probablement le problème. – James

+0

Comment exécutez-vous la requête? Dans le navigateur de requête MySQL? D'un langage de programmation? Si ce dernier, quelle langue, et pouvez-vous poster la partie pertinente du code? Aussi, pourquoi avez-vous besoin de lire 2 millions de lignes? Que ferez-vous avec toutes ces données? –

+1

Et publier la sortie de 'EXPLAIN SELECT ...' pour votre requête, et la sortie de 'SHOW CREATE TABLE big_table' et' SHOW CREATE TABLE small_table'. –

Répondre

3

Vous sélectionnez environ 2 millions de disques en un seul question. Selon la quantité de données dans chaque ligne, il peut s'agir de centaines de mégaoctets de données que vous demandez.

Les choses que vous pourriez vouloir essayer:

  • Si vous n'avez pas besoin de toutes les colonnes pour les interroger alors colonnes dont vous avez besoin au lieu d'utiliser SELECT table.*.
  • Voyez si vous pouvez déplacer une partie (ou la totalité) du traitement à la base de données au lieu d'aller chercher les données et le traitement dans le client.
  • Évitez de lire l'intégralité du jeu de résultats en mémoire en une fois.
  • Process les lignes de lots de quelques milliers à la fois plutôt que d'aller chercher tous à la fois.
+0

Oui, bien sûr, si vous limitez le jeu de résultats avec "WHERE" ou "LIMIT", cela accélèrera, mais la requête ne fera pas ce que je veux. Je veux vraiment traiter tous les 2 millions de disques, alors comment cela m'aiderait-il? Ou proposez-vous que je transforme cette requête en plusieurs petites requêtes avec "LIMIT 0, 10000", "LIMIT 100001, 200000", etc? Dans ma naïveté j'aurais supposé que ce dernier ne devrait pas être nécessaire ou utile ... –

+1

@Michal McGowan: Quel genre de traitement? Avez-vous examiné s'il est possible de traiter les données dans la base de données au lieu de les transmettre au client pour traitement? Je pense aussi que ce serait une bonne idée de poster le code Java que vous utilisez pour exécuter la requête et lire les résultats. Vous pouvez avoir un problème là-bas. Si possible, vous souhaitez traiter une ligne à la fois plutôt que de lire l'ensemble des résultats en une seule fois. Le découper en lots peut également être une bonne idée, mais l'utilisation d'une LIMITE avec un décalage n'est pas la meilleure façon de le faire car cela deviendra de plus en plus lent au fur et à mesure que le décalage augmentera. –

+0

Je pense que le traitement dans la base de données accomplira beaucoup de ce que je voulais; Merci. Pour une raison que j'ignorais, je ne me rendais pas bêtement compte que le choix mettrait le tout en mémoire. –