2012-08-22 27 views
6
SELECT r.*, u.username 
FROM `reservation` AS r JOIN 
    `users` AS u 
WHERE u.id = r.user_id 
AND DATE(r.bx_date) >= DATE('2012-08-22') 
AND DATE(r.bx_date) <= DATE('2012-08-22') 
AND r.status='1' 
ORDER BY r.id desc 

bx_date - fecha de reserva.¿Cómo optimizar la consulta a continuación?

Lleva más de 8 segundos ejecutar esta consulta. Tengo más de 500,000 registros en la tabla de reservas y 40,000 registros en la tabla de usuarios.

No he realizado ninguna optimización en las tablas de mi base de datos. Nada en absoluto. Sólo PKs solo. ¿Cómo puedo optimizar esta consulta? ¿Cuáles son las opciones para aumentar el rendimiento de esta base de datos?

Gracias

Reserva de mesas:

CREATE TABLE `reservation` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`user_id` int(10) unsigned NOT NULL COMMENT 'User ID', 
`tx_id` varchar(15) NOT NULL COMMENT 'Transaction ID', 
`tx_date` datetime NOT NULL COMMENT 'Transaction Date', 
`bx_date` date NOT NULL COMMENT 'Booking Date', 
`theater_id` int(10) unsigned NOT NULL COMMENT 'Theater ID', 
`movie_id` int(10) unsigned NOT NULL COMMENT 'Movie ID', 
`showtime_id` int(10) unsigned NOT NULL COMMENT 'Show Time ID', 
`category_id` int(10) unsigned NOT NULL COMMENT 'Category ID', 
`full_tickets` tinyint(2) unsigned NOT NULL COMMENT 'Number of Full Tickets', 
`half_tickets` tinyint(2) unsigned NOT NULL COMMENT 'Number of Half Tickets', 
`no_seats` tinyint(3) unsigned NOT NULL COMMENT 'No of Seats', 
`full_ticket_price` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT 'Full Ticket Price', 
`half_ticket_price` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT 'Half Ticket Price', 
`amount` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT 'Total Amount', 
`method` tinyint(1) unsigned NOT NULL COMMENT 'Payment Method 1=web 2=mobile 3=theater', 
`paymentgateway_id` int(10) unsigned NOT NULL COMMENT 'Payment Gateway ID', 
`payment_type` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0 = Cash 1=Credit Card', 
`status` tinyint(1) unsigned NOT NULL COMMENT 'Status 0=provisional 1=booked 2=canceled 3=auto canceld', 
`comment` text, 
`reservation_type` tinyint(1) unsigned NOT NULL COMMENT 'Reservation Type 0=complimentary 1=advamce booking 2=Mobile Booking, 3 - Theater Offline Booking', 
`complimentary_type` tinyint(1) unsigned NOT NULL COMMENT '0=none 1=loyalty rewards 2=marketing 3=promotional 4=show blocking 5=vip', 
`description` mediumtext NOT NULL COMMENT 'Complimentary Description', 
`title` varchar(10) DEFAULT NULL COMMENT 'Title', 
`fname` varchar(255) DEFAULT NULL COMMENT 'First Name', 
`lname` varchar(255) DEFAULT NULL COMMENT 'Last Name', 
`gender` tinyint(1) unsigned DEFAULT NULL COMMENT 'Gender 0=male 1=female', 
`dob` date DEFAULT '0000-00-00' COMMENT 'Date of Birth', 
`nic` varchar(10) DEFAULT NULL COMMENT 'NIC no', 
`address` text COMMENT 'Address Line 1', 
`city` varchar(255) DEFAULT NULL COMMENT 'City', 
`district` varchar(50) DEFAULT NULL COMMENT 'District ', 
`country` varchar(255) DEFAULT NULL COMMENT 'Country', 
`mobile` varchar(15) DEFAULT NULL COMMENT 'Mobile No', 
`contact_phone` varchar(15) DEFAULT NULL COMMENT 'Fixed Land Phone Number', 
`email` varchar(255) DEFAULT NULL COMMENT 'Email Address', 
`timer` int(4) unsigned NOT NULL, 
PRIMARY KEY (`id`), 
KEY `user_id_index` (`user_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=555706 DEFAULT CHARSET=utf8 

usuarios Tabla:

CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT, 
title varchar(100) NOT NULL, 
name varchar(255) NOT NULL DEFAULT '', 
last_name varchar(255) NOT NULL, 
username varchar(150) NOT NULL DEFAULT '', 
email varchar(100) NOT NULL DEFAULT '', 
password varchar(100) NOT NULL DEFAULT '', 
usertype varchar(25) NOT NULL DEFAULT '', 
block tinyint(4) NOT NULL DEFAULT '0', 
sendEmail tinyint(4) DEFAULT '0', 
registerDate datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
lastvisitDate datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
activation varchar(100) NOT NULL DEFAULT '', 
params text NOT NULL, 
gender varchar(6) NOT NULL, 
date_of_birth date NOT NULL, 
nic_no varchar(10) NOT NULL, 
address varchar(255) NOT NULL, 
city varchar(100) NOT NULL, 
district varchar(100) NOT NULL, 
mobile varchar(15) NOT NULL, 
subscribe_sms tinyint(1) NOT NULL, 
contact_phone varchar(15) NOT NULL, 
newsletter_subscribe tinyint(1) NOT NULL, 
PRIMARY KEY (id), 
UNIQUE KEY username (username), 
KEY usertype (usertype), 
KEY idx_name (name), 
KEY idx_block (block), 
KEY email (email)) 
ENGINE=InnoDB AUTO_INCREMENT=34265 DEFAULT CHARSET=utf8 
+2

nos muestras la salida de SHOW CREATE TABLE reservation', '' de los usuarios SHOW CREATE TABLE y la explican desde el selecto informados aquí? (Simplemente ejecute la selección, pero con la palabra 'EXPLAIN' frente a ella). – Konerak

+2

-1 porque ni siquiera has intentado optimizarlo. Al menos incluya la salida de 'EXPLAIN' y diga qué cosas de https://dev.mysql.com/doc/refman/5.6/en/optimization.html ha intentado. –

+1

¿Qué tipo de datos es 'bx_date'? – Bridge

Respuesta

3

En primer lugar me gustaría volver a escribir la consulta como la siguiente:

SELECT r.*, u.username 
FROM 
`reservation` AS r 
INNER JOIN `users` AS u ON u.id = r.user_id 
WHERE 
r.bx_date = '2012-08-22' /* or use BETWEEN when you really have a range */ 
AND r.status='1' 
ORDER BY r.id desc 

en la unión interna es simplemente un di una sintaxis diferente a la suya, pero hace lo mismo. En mi opinión, este es menos propenso a errores y más amigable, ya que no es necesario separar en la cláusula WHERE qué es un join y qué no.

Como la columna bx_date es del tipo DATE, no necesita la función DATE() para volver a ponerle fecha. En general, el uso de una función en una columna impide el uso de un índice (si existe en esa columna).

Para mantener las cosas simples desde el principio, simplemente comience agregando índices a las columnas que se utilizan con frecuencia para las uniones o se utilizan en las cláusulas WHERE.

En su caso, las columnas utilizadas para JOIN ya son claves principales, por lo que implícitamente ya tienen un índice.

Puede añadir un índice como esto:

ALTER TABLE reservation ADD INDEX idx_reservation_bx_date (bx_date); /*if I remember correctly :) */ 

Para más información leer here.

También puede usar índices compuestos, estos son índices en varias columnas.

ACTUALIZACIÓN Gracias a ypercube a sugerir en los comentarios:

ALTER TABLE reservation ADD INDEX idx_reservation_bx_date_status (bx_date, status); /*if I remember correctly :) */ 

entonces usted puede comprobar si o qué índice se utiliza poniendo EXPLAIN delante de la consulta. Y, por supuesto, debe medir, medir y medir si un índice es bueno o no. La sobreindexación tampoco es una buena idea, ya que INSERTOS y ACTUALIZACIONES se vuelven mucho más lentos. Para ver si un índice se sujeta a su consulta que tiene que asegurarse de que no está en la memoria caché en algún lugar, por lo que sólo permite probar ejecutar la consulta con SQL_NO_CACHE así:

SELECT SQL_NO_CACHE r.*, u.username 
FROM 
`reservation` AS r 
INNER JOIN `users` AS u ON u.id = r.user_id 
WHERE 
r.bx_date = '2012-08-22' /* or use BETWEEN when you really have a range */ 
AND r.status='1' 
ORDER BY r.id desc; 

-

</UPDATE> 

Otra regla es , que no es una buena idea indexar columnas que tienen muy pocos valores distintos cuando la tabla tiene muchas filas.Su columna de estado en la reserva solo tiene 4 valores distintos. Agregar un índice en esta columna hace que el índice sea inútil. Incluso puede empeorar, ya que MySQL podría usar el índice y luego tiene que hacer una búsqueda adicional para encontrar los datos reales correspondientes a la posición del índice.

Una lectura muy buena de esto es Use-the-index-Luke

+0

Probablemente es una buena idea tener un índice compuesto aquí, ya sea en '(bx_date, status)' o en '(status, bx_date)' –

+0

@ ypercube Sí, buena idea, agregó eso. – fancyPants

+0

gracias por la asistencia – Techie

Cuestiones relacionadas