2012-08-22 33 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 - ngày đã đặt.Làm cách nào để tối ưu hóa truy vấn bên dưới?

Mất hơn 8 giây để chạy truy vấn này. Tôi có hơn 500.000 bản ghi trong bảng đặt chỗ và 40.000 bản ghi trong bảng người dùng.

Tôi chưa thực hiện bất kỳ tối ưu hóa nào cho các bảng cơ sở dữ liệu của mình. Không có gì đâu. Chỉ PK thôi. Làm cách nào để tối ưu hóa truy vấn này? Các tùy chọn để tăng hiệu suất của cơ sở dữ liệu này là gì.

Cảm ơn

Đặt bàn:

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 

Bảng người dùng:

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

Bạn có thể cho chúng ta thấy đầu ra từ 'HIỂN THỊ CREATE TABLE reservation',' HIỂN THỊ CREATE TABLE users' và GIẢI THÍCH từ chọn bạn đăng ở đây? (Chỉ cần thực hiện lựa chọn, nhưng với từ 'EXPLAIN' ở phía trước nó). – Konerak

+2

-1 bởi vì bạn thậm chí không cố gắng tối ưu hóa nó. Ít nhất bao gồm đầu ra của 'GIẢI THÍCH' và nói nội dung nào từ https://dev.mysql.com/doc/refman/5.6/en/optimization.html bạn đã thử. –

+1

Kiểu dữ liệu nào là 'bx_date'? – Bridge

Trả lời

3

Trước tiên tôi xin viết lại truy vấn như thế này:

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 

INNER JOIN chỉ là a di cú pháp fferent hơn của bạn, nhưng nó cũng vậy. Theo tôi, đây là lỗi ít dễ bị lỗi và thân thiện với mắt hơn, vì bạn không phải tách biệt trong mệnh đề WHERE liên kết là gì và không có gì.

Vì cột bx_date thuộc loại DATE bạn không cần chức năng DATE() để thực hiện lại ngày. Nói chung việc sử dụng một hàm trên một cột ngăn cản việc sử dụng một chỉ mục (nếu tồn tại trên cột đó).

Để giữ cho mọi thứ đơn giản ngay từ đầu, chỉ cần bắt đầu bằng cách thêm chỉ mục vào các cột thường được sử dụng để tham gia hoặc được sử dụng trong mệnh đề WHERE.

Trong trường hợp của bạn, các cột được sử dụng cho JOIN là các khóa chính, vì vậy chúng hoàn toàn đã có chỉ mục.

Bạn có thể thêm một chỉ số như thế này:

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

Để biết thêm thông đọc here.

Bạn cũng có thể sử dụng chỉ mục tổng hợp, đây là các chỉ mục trên nhiều cột.

CẬP NHẬT Nhờ ypercube của đề nghị trong ý kiến:

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

Sau đó bạn có thể kiểm tra xem hoặc những gì chỉ số được sử dụng bằng cách đặt một EXPLAIN trước truy vấn của bạn. Và tất nhiên bạn phải đo lường, đo lường và đo lường nếu một chỉ số là tốt hay không. Overindexing cũng không phải là một ý tưởng tốt, vì INSERTS và UPDATES trở nên chậm hơn nhiều. Để xem nếu một chỉ số fastens truy vấn của bạn, bạn phải chắc chắn rằng nó không có trong bộ nhớ cache ở đâu đó, vì vậy chỉ cần để kiểm tra thực hiện truy vấn của bạn với SQL_NO_CACHE như thế này:

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> 

quy tắc khác là , đó không phải là ý tưởng hay khi lập chỉ mục các cột có rất ít giá trị riêng biệt khi bảng có nhiều hàng.Cột trạng thái của bạn trong đặt chỗ chỉ có 4 giá trị riêng biệt. Việc thêm chỉ mục vào cột này sẽ làm cho chỉ mục vô dụng. Nó thậm chí có thể tồi tệ hơn, vì MySQL có thể sử dụng chỉ mục và sau đó phải thực hiện tìm kiếm thêm để tìm dữ liệu thực tế tương ứng với vị trí chỉ mục.

Một đọc rất tốt về nó là Use-the-index-Luke

+0

Đây có thể là một ý tưởng tốt mặc dù có một số hợp chất ở đây, hoặc '(bx_date, tình trạng)' hoặc '(trạng thái, bx_date)' –

+0

@ ypercube Vâng, ý tưởng hay, thêm vào đó. – fancyPants

+0

nhờ hỗ trợ – Techie

Các vấn đề liên quan