2012-02-22 15 views
5

MySQL Server versione: 5.1.41 su Ubuntu 10.04MySQL viste o vs clausola IN

mi sono imbattuto in una differenza di comportamento di MySQL quando si modificano alcune query e voleva sapere la ragione per questo.

Fondamentalmente sto creando una vista. Quando interrogo la visualizzazione, il set di risultati è lo stesso Tuttavia, il numero di righe lette è diverso per una clausola IN rispetto a una clausola OR. Sotto sotto è un semplice esempio:

CREATE TABLE country ( 
    id_country int(11) NOT NULL AUTO_INCREMENT, 
    name varchar(50) NOT NULL, 
    PRIMARY KEY (id_country) 
) ENGINE=InnoDB; 

INSERT INTO country (name) VALUES ('A'), ('B'), ('C'), ('D'), ('E'), ('F'), ('G'), ('H'); 

CREATE TABLE status ( 
    id_status int(11) NOT NULL AUTO_INCREMENT, 
    id_country int(11) NOT NULL, 
    status tinyint(4) NOT NULL, 
    PRIMARY KEY (id_status) 
) ENGINE=InnoDB; 
ALTER TABLE status ADD INDEX (id_country); 
ALTER TABLE status ADD FOREIGN KEY (id_country) REFERENCES test.country (id_country) ON DELETE RESTRICT ON UPDATE RESTRICT ; 

INSERT INTO status(id_country, status) VALUES 
(1,0), (2,1), (3,0), (4,1), (5,0),(6,1), (7,0), (8,1); 

CREATE ALGORITHM=MERGE VIEW view_country 
AS 
    SELECT c.*, s.id_status, s.status 
    FROM country c JOIN status s ON c.id_country = s.id_country; 

Il 2 spiegano le dichiarazioni che seguono mostrano diverso numero di righe analizzato

mysql> EXPLAIN EXTENDED SELECT * FROM view_country WHERE id_country IN (1, 2, 3)\G; 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: range 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: NULL 
     rows: 3 
    filtered: 100.00 
     Extra: Using where 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: s 
     type: ref 
possible_keys: id_country 
      key: id_country 
     key_len: 4 
      ref: test.c.id_country 
     rows: 1 
    filtered: 100.00 
     Extra: 
2 rows in set, 1 warning (0.00 sec) 

Utilizzando la clausola OR

mysql> EXPLAIN EXTENDED SELECT * FROM view_country WHERE id_country = 1 OR id_country = 2 OR id_country = 3\G; 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: s 
     type: ALL 
possible_keys: id_country 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 8 
    filtered: 37.50 
     Extra: Using where 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: test.s.id_country 
     rows: 1 
    filtered: 100.00 
     Extra: 
2 rows in set, 1 warning (0.00 sec) 

Se si guardano le "righe "in entrambe le query - si sommano in modo diverso

La query conLa clausolalegge meno righe rispetto a IN, che si aggiunge a tabelle e join enormi.

Qualcuno può aiutarmi a capire perché è così?

Grazie per il vostro tempo.

+0

Coerentemente lo stesso, ma risultati diversi? –

+0

@Marcus - io sono sy non ho capito la domanda - se volevi ottenere sempre un risultato coerente ogni volta e il numero di righe analizzate ogni volta è anche coerente - allora la risposta è sì – naveen

+0

@Marcus Adams - c'era una copia incolla errore mio da parte mia - l'ho corretto. Il problema non riguarda set di risultati diversi: i set di risultati sono uguali, ma il numero di righe lette è diverso tra IN e OR - fammi sapere se non sei in grado di riprodurlo - sono sulla versione server: 5.1 – naveen

risposta

1

Si prega di notare che i piani di esecuzione hanno molto a che fare con lo stato di indici e le dimensioni delle tabelle. MySQL può essere eseguito in modo diverso anche per query simili, e talvolta MySQL può persino indovinare.

La vista con il JOIN complica sicuramente le cose, quindi la tua istruzione SELECT non è così semplice. Non sorprenderti dal fatto che MySQL scelga un piano di esecuzione diverso per IN rispetto a OR.

Nel caso della prima query, MySQL ha scelto di utilizzare gli indici per entrambe le query, il che risulta nel conteggio di righe specifico e accurato in EXPLAIN.

Tuttavia, nella seconda query, MySQL ha scelto di eseguire la scansione di tutte le righe nella tabella di stato. Questo ha senso dal momento che ci sono così poche righe e MySQL deve visitare la tabella comunque perché non esiste un indice di copertura che restituirà tutte le righe necessarie. Non sarei sorpreso se la seconda query non fosse effettivamente più veloce della prima. Inoltre, tieni presente che il conteggio delle righe (per le scansioni) in EXPLAIN è una stima, quindi prendilo in considerazione durante la profilazione delle query.

La prima query deve eseguire 6 ricerche, mentre la seconda query deve eseguire solo 3 ricerche dopo una scansione della tabella molto breve.

Ci sono molti trucchi che MySQL a volte si limitano a scenari molto specifici per cercare di ottimizzare la query, in base agli indici correnti e ai conteggi delle righe. Esistono casi documentati in cui, for similar queries, MySQL will take two different approaches and end up with the same execution path. Ci sono altri casi in cui due piani di esecuzione completamente diversi danno risultati simili, e questo è uno di quei casi.

In ogni caso, spero che questo ti spieghi perché c'è una differenza, ma fintanto che i risultati sono gli stessi e le prestazioni sono simili, non c'è nulla di cui preoccuparsi.

In alcuni casi, come ho detto prima, MySQL non farà la migliore ipotesi, e quindi è possibile utilizzare strumenti come indici e join naturali. Nel tuo caso, penso che MySQL si stia comportando bene.

Per le prestazioni di ricerca ed esecuzione piani più controllare le due seguenti siti:

+0

grazie per la spiegazione Marcus - come buona pratica, penso di dover passare attraverso tutte le query di join complesse e vedere come mysql seleziona gli indici – naveen

0

Se ho capito bene, i risultati ottenuti sono gli stessi e ti piacerebbe sapere la differenza tra la clausola "OR" e "IN" per quanto riguarda la velocità e il loro funzionamento.

Se è così, che penso che la tua domanda è un possibile duplicato di questo: IN vs OR in the SQL WHERE Clause

+0

Credo che il PO indichi che i risultati sono diversi usando "IN" al contrario di "OR" –

+0

Ah ok, quindi non ho capito bene la sua domanda. Avrei pensato che i risultati sarebbero stati gli stessi. – Honnes

+0

@ZackMacomber, dalla domanda: * "il set di risultati è lo stesso" *. –