2010-02-25 9 views
6

Estoy tratando de enumerar toda la información de book_sales para un autor de libros en particular. Así que tengo una consulta y no usa el índice para buscar registros.php & mySQL: Query no utiliza el índice en la tabla join

La siguiente es mi estructura de las tablas:

-- Table structure for table `books` 

CREATE TABLE IF NOT EXISTS `books` (
    `book_id` int(11) NOT NULL auto_increment, 
    `author_id` int(11) unsigned NOT NULL, 
    `book_type_id` int(11) NOT NULL, 
    `book_title` varchar(50) NOT NULL, 
    `book_price` smallint(4) NOT NULL, 
    `in_stock` char(1) NOT NULL, 
    PRIMARY KEY (`book_id`), 
    KEY `book_type_id` (`book_type_id`), 
    KEY `author_id` (`author_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

-- Dumping data for table `books` 

INSERT INTO `books` (`book_id`, `author_id`, `book_type_id`, `book_title`, `book_price`, `in_stock`) VALUES 
(1, 1, 1, 'My Book 1', 10, 'y'), 
(2, 2, 1, 'My Book 2', 20, 'n'), 
(3, 1, 2, 'My Book 3', 30, 'y'), 
(4, 3, 3, 'My Book 4', 40, 'y'), 
(5, 4, 2, 'My Book 5', 50, 'n'), 
(6, 1, 1, 'My Book 6', 60, 'y'), 
(7, 5, 3, 'My Book 7', 70, 'n'), 
(8, 6, 2, 'My Book 8', 80, 'n'), 
(9, 7, 1, 'My Book 9', 90, 'y'), 
(10, 8, 3, 'My Book 10', 100, 'n'); 

-- Table structure for table `book_sales` 

CREATE TABLE IF NOT EXISTS `book_sales` (
    `sale_id` int(11) NOT NULL auto_increment, 
    `book_id` int(11) NOT NULL, 
    `sale_amount` decimal(8,2) NOT NULL default '0.00', 
    `time` datetime NOT NULL default '0000-00-00 00:00:00', 
    `price` smallint(8) NOT NULL, 
    PRIMARY KEY (`sale_id`), 
    KEY `book_id` (`book_id`), 
    KEY `price` (`price`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

-- Dumping data for table `book_sales` 

INSERT INTO `book_sales` (`sale_id`, `book_id`, `sale_amount`, `time`, `price`) VALUES 
(1, 1, '10.00', '2010-02-23 10:00:00', 20), 
(2, 1, '20.00', '2010-02-24 11:00:00', 20); 

Mi Pregunta:

SELECT sale_amount, price 
FROM book_sales 
INNER JOIN books ON book_sales.book_id = books.book_id 
WHERE books.author_id =1 

Un explique en lo anterior, me demuestra:

id select_type table  type  possible_keys  key  key_len ref  rows  Extra 
1 SIMPLE   books  ref  PRIMARY,author_id author_id 4   const 3  Using index 
1 SIMPLE   book_sales ALL  book_id    NULL  NULL  NULL  2  Using where 

Claramente, book_sales no está usando la clave 'book_id', aunque yo la tengo. ¿Qué puedo hacer para que la tabla book_sales use el índice?

Gracias.

ediciones hechas en base a sugerencias (pero el resultado es que todavía no utilizan índice):

//Does not use the index in book_sales table 
EXPLAIN SELECT sale_amount, price 
FROM books, book_sales 
FORCE INDEX (book_id) 
WHERE book_sales.book_id = books.book_id 
AND books.author_id =1 

//Does not use the index in book_sales table 
EXPLAIN SELECT sale_amount, price 
FROM book_sales, books 
WHERE books.author_id = 1 
AND book_sales.book_id = books.book_id 

de cómo forzar la tabla book_sale con sólo 2 filas, utilizar el índice? Gracias.

Respuesta

12

Como se puede ver en el explicar "book_id" aparece como una clave posible. Si MySQL no lo usa, es solo que el optimizador no cree que acelere la consulta. Lo cual es cierto si "book_sales" solo tiene 2 filas, y el 100% de esas filas comparten el mismo "book_id". Se llama cardinalidad por cierto. How to Avoid Table Scans (Manual de MySQL)

Intenta rellenarlo con más filas y deberías ver que MySQL usará un índice para la unión.

Editar: la consulta

SELECT sale_amount, price 
FROM books, book_sales 
FORCE INDEX (book_id) 
WHERE book_sales.book_id = books.book_id 
AND books.author_id =1 

... no va a funcionar bien en este caso porque el optimizador todavía reconoce que la lectura del índice es subóptima y cambia el orden de la tabla para evitar hacerlo. Puede forzar el orden de la tabla usando STRAIGHT_JOIN. Sin embargo, esto es un poco complicado porque forza a MySQL a ejecutar la consulta de una manera que no es la mejor.

 EXPLAIN 
     SELECT sale_amount, price 
     FROM books 
STRAIGHT_JOIN book_sales FORCE INDEX (book_id) ON book_sales.book_id = books.book_id 
     WHERE books.author_id = 1 
+2

Exactamente. Normalmente, un índice lo desacelerará si está seleccionando más del 25% de la tabla. –

+0

+1 Eso es verdadero y válido en todos los casos. – streetparade

+0

@Josh Davis Gracias por la respuesta.Como sugirió, llené la tabla con datos adicionales y cuando intenté la consulta que tenía inicialmente, ¡funcionó! ¡La tabla book_sales estaba usando la tecla book_id! Alivio finalmente !!! Así que aquí el culpable fue el registro de consultas lento mysql. Lo tenía activado y estaba registrando todas las consultas que no usaban el índice y esta consulta apareció en el registro y mi batalla comenzó con eso. Entonces, ¿hay alguna forma de que pueda suprimir este registro para que no muestre las consultas del tipo anterior? ¡Muchas gracias! – Devner

0

probar este

SELECT sale_amount, price 
FROM book_sales,books 
LEFT JOIN books ON(book_sales.book_id = books.book_id) 
WHERE books.author_id =1 
+0

Gracias por la respuesta. Probé tu código. Obtuve el error "# 1066 - Tabla no única/alias: 'libros'". Así que eliminé ", books" en la cláusula FROM. Hizo una explicación y todavía no usa el índice. ¿Hay algo más que podamos hacer para arreglar esto? – Devner

+0

Hy Devner Por favor, siga la respuesta de Josh Davis – streetparade

+0

Lo hice y visité el enlace que publicó. Veo una opción llamada "--max-busca-por-clave = 1000". Dice: "Comience mysqld con la opción --max-busca-por-clave = 1000 o use SET max_seeks_for_key = 1000 para decirle al optimizador que asuma que ningún escaneo de clave causa más de 1000 búsquedas de clave". No estoy seguro de lo que esto realmente significa. ¿Puedes arrojar algo de luz sobre esto? Gracias. – Devner

Cuestiones relacionadas