Domanda

Domanda 1:

select distinct email from mybigtable where account_id=345

prende 0.1s

Domanda 2:

Select count(*) as total from mybigtable where account_id=123 and email IN (<include all from above result>)

prende 0.2s

Domanda 3:

Select count(*) as total from mybigtable where account_id=123 and email IN (select distinct email from mybigtable where account_id=345)

richiede 22 minuti e 90% sua nello stato "preparazione". Perché questo prende così tanto tempo.

Tabella è InnoDB con file 3.2mil su MySQL 5.0

È stato utile?

Soluzione

In Query 3, si sono fondamentalmente eseguendo una subquery per ogni riga di mybigtable contro se stessa.

Per evitare questo, è necessario fare due importanti modifiche:

grande cambiamento # 1: Refactor Query

Ecco la vostra query originale

Select count(*) as total from mybigtable
where account_id=123 and email IN
(select distinct email from mybigtable where account_id=345)

Si potrebbe provare

select count(*) EmailCount from
(
    select tbl123.email from
    (select email from mybigtable where account_id=123) tbl123
    INNER JOIN
    (select distinct email from mybigtable where account_id=345) tbl345
    using (email)
) A;

o forse il conteggio per e-mail

select email,count(*) EmailCount from
(
    select tbl123.email from
    (select email from mybigtable where account_id=123) tbl123
    INNER JOIN
    (select distinct email from mybigtable where account_id=345) tbl345
    using (email)
) A group by email;

grande cambiamento # 2: corretta indicizzazione

Penso che tu abbia questo già dal Query 1 e Query 2 correre veloce. Assicurarsi di avere un indice composto sul (ACCOUNT_ID, e-mail). Fare SHOW CREATE TABLE mybigtable\G e assicuratevi di avere uno. Se non ce l'hai, o se non siete sicuri, quindi si crea l'indice in ogni caso:

ALTER TABLE mybigtable ADD INDEX account_id_email_ndx (account_id,email);

UPDATE 2012-03-07 13:26 EST

Se si vuole fare un NOT IN (), modificare il INNER JOIN ad un LEFT JOIN e controllare per il lato destro essendo NULL, in questo modo:

select count(*) EmailCount from
(
    select tbl123.email from
    (select email from mybigtable where account_id=123) tbl123
    LEFT JOIN
    (select distinct email from mybigtable where account_id=345) tbl345
    using (email)
    WHERE tbl345.email IS NULL
) A;

UPDATE 2012-03-07 14:13 EST

Si prega di leggere questi due link sul fare join

Qui è un grande video di YouTube dove ho imparato a query refactoring e il libro si basava su

Altri suggerimenti

In MySQL, sottoselezioni all'interno della clausola sono ri-eseguito per ogni riga della query esterna, creando così O (n ^ 2). Il racconto è, non utilizzare IN (SELECT).

  1. Avete un indice su ACCOUNT_ID?

  2. Il secondo problema potrebbe essere con le nidificati sub-query che hanno prestazioni terribile in 5.0.

  3. GROUP BY con una clausola having è più veloce di DISTINCT.

  4. Che cosa stai cercando di fare che può essere meglio fatto attraverso unisce in aggiunta alla voce # 3?

C'è un sacco di elaborazione coinvolti nella manipolazione di una subquery IN () come la vostra. Si può leggere di più su di esso qui .

Il mio primo suggerimento sarebbe quello di tentare di riscrivere il subquery in una JOIN invece. Qualcosa di simile (non testato):

SELECT COUNT(*) AS total FROM mybigtable AS t1
 INNER JOIN 
   (SELECT DISTINCT email FROM mybigtable WHERE account_id=345) AS t2 
   ON t2.email=t1.email
WHERE account_id=123
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top