2010-02-25 31 views
6

Tôi đang cố liệt kê tất cả thông tin book_sales cho tác giả sách cụ thể. Vì vậy, tôi có một truy vấn và nó không sử dụng Index để tra cứu các bản ghi.php & mySQL: Truy vấn không sử dụng chỉ mục trong bảng tham gia

Sau đây là cấu trúc bảng của tôi:

-- 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); 

Query của tôi:

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

Một GIẢI THÍCH trên trên, chỉ cho tôi:

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 

Rõ ràng, book_sales không sử dụng khóa 'book_id', mặc dù tôi có nó. Tôi có thể làm gì để làm cho bảng book_sales sử dụng chỉ mục?

Cảm ơn bạn.

chỉnh sửa được thực hiện dựa trên đề xuất (nhưng kết quả là họ vẫn không sử dụng index):

//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 

Làm thế nào để buộc các bảng book_sale chỉ với 2 hàng, sử dụng các chỉ số? Cảm ơn bạn.

Trả lời

12

Như bạn có thể nhìn thấy trong giải thích, "book_id" được liệt kê như là một chìa khóa có thể. Nếu MySQL không sử dụng nó, nó chỉ là trình tối ưu hóa không nghĩ rằng nó sẽ tăng tốc độ truy vấn. Điều này đúng nếu "book_sales" chỉ có 2 hàng và 100% các hàng đó chia sẻ cùng một "book_id". Nó được gọi là btw cardinality. How to Avoid Table Scans (Hướng dẫn sử dụng MySQL)

Hãy thử điền nó với nhiều hàng hơn và bạn sẽ thấy rằng MySQL sẽ sử dụng chỉ mục để tham gia.

Edit: các truy vấn

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 

... sẽ không làm việc, hoặc trong trường hợp đó vì tôi ưu hoa vẫn nhận ra rằng đọc chỉ số này không tối ưu và công tắc thứ tự bảng để tránh làm như vậy. Bạn có thể buộc thứ tự bảng bằng cách sử dụng STRAIGHT_JOIN. Đây là, tuy nhiên, một chút của một hack vì nó buộc MySQL để thực hiện các truy vấn theo một cách mà không phải là tốt nhất.

 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

Chính xác. Thông thường một chỉ mục sẽ làm chậm bạn xuống nếu bạn đang chọn nhiều hơn 25% của bảng. –

+0

+1 Thats đúng và hợp lệ trong mọi trường hợp. – streetparade

+0

@Josh Davis Cảm ơn bạn đã trả lời.Như bạn đã đề xuất, tôi đã điền vào bảng với dữ liệu bổ sung và khi tôi thử truy vấn mà tôi đã có với tôi ban đầu, nó đã hoạt động! Bảng book_sales đã sử dụng khóa book_id !!! Cứu trợ cuối cùng !!! Vì vậy, ở đây thủ phạm là nhật ký truy vấn chậm mysql. Tôi đã bật tính năng này và đang ghi nhật ký tất cả các truy vấn không sử dụng chỉ mục và truy vấn này hiển thị trong nhật ký và trận chiến của tôi bắt đầu với nó. Vì vậy, có cách nào tôi có thể ngăn chặn đăng nhập này từ hiển thị các truy vấn của loại trên? Cảm ơn nhiều! – Devner

0

Hãy thử điều này

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

Cảm ơn bạn đã trả lời. Tôi đã thử mã của bạn. Có "# 1066 - Lỗi/bảng bí danh không phải là duy nhất: 'sách'". Vì vậy, tôi đã xóa ", sách" trong mệnh đề FROM. Đã giải thích và nó vẫn không sử dụng chỉ mục. Bất cứ điều gì khác mà chúng ta có thể làm để sửa lỗi này? – Devner

+0

Hy Devner Hãy làm theo câu trả lời của Josh Davis – streetparade

+0

Tôi đã làm và tôi đã truy cập vào liên kết mà anh ấy đã đăng. Tôi thấy một tùy chọn có tên "--max-seeks-for-key = 1000". Nó nói: "Bắt đầu mysqld với tùy chọn --max-seeks-for-key = 1000 hoặc sử dụng SET max_seeks_for_key = 1000 để cho trình tối ưu hóa giả định rằng không có lần quét khóa nào gây ra hơn 1.000 lần tìm kiếm chính". Tôi không chắc điều này thực sự có ý nghĩa gì. Bạn có thể ném bất kỳ ánh sáng vào điều này? Cảm ơn bạn. – Devner

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