2011-11-07 51 views
11

Trong những ngày qua tôi nhận thấy có điều gì đó kỳ lạ tối ưu hóa truy vấn của mình. Tôi có một câu hỏi đơn giản mà làm điều gì đó như:MYSQL - NOT vs var = false

SELECT id,name,amount FROM reservations WHERE NOT canceled ORDER BY name ASC 

tôi nhận thấy mysql đã không sử dụng bất kỳ chỉ số, vì vậy tôi bắt đầu làm một số thí nghiệm. Vô tình tôi thay thế "NOT cancel" bằng "cancel = false", và sau đó, Mysql bắt đầu sử dụng "cancel" làm chỉ mục. Sau đó tôi đã thử sử dụng đối diện:

SELECT ... FROM reservations WHERE canceled ORDER BY ... 

Kết quả tương tự! Khi tôi thay đổi điều đó thành "cancel = true", chỉ mục sẽ hoạt động trở lại.

Câu hỏi của tôi là: HOW COME ?! Không sử dụng "KHÔNG" cách "thanh lịch"? Dù sao thì tôi cũng không mong đợi nó tạo nên sự khác biệt nào.

Tôi đang sử dụng InnoDB làm công cụ, nhưng tôi nhận được kết quả tương tự bằng cách sử dụng MyISAM. Ai đó có thể làm rõ mọi thứ không? Cảm ơn.

Edit: Bảng cấu trúc

CREATE TABLE `reservations` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `trip_code` varchar(10) DEFAULT NULL, 
    `departure_date` date DEFAULT NULL, 
    `amount` float DEFAULT NULL, 
    `name` varchar(45) DEFAULT NULL, 
    `canceled` tinyint(1) NOT NULL DEFAULT '0', 
    `created_date` date NOT NULL, 
    `creator_user` int(11) NOT NULL DEFAULT '1', 
    `last_update_user` int(11) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    KEY `trip_code` (`trip_code`), 
    KEY `departure_date` (`departure_date`), 
    KEY `created_date` (`created_date`), 
    KEY `canceled` (`canceled`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=123181 ; 
+0

bạn sử dụng phiên bản nào? – neworld

+0

Phiên bản máy chủ: 5.1.43-cộng đồng – Phoenix

+0

Bạn có thể đăng lên DDL của bảng hay không. –

Trả lời

2

Tôi không quen thuộc với MYSQL, nhưng suy nghĩ một cách logic, tôi hiểu nó như thế này:
Index cũng giống như một danh bạ điện thoại, khi bạn đang tìm kiếm "Cohen", bạn có thể lấy nó ngay lập tức.
Nhưng nếu bạn đang tìm kiếm NOT "Cohen", bạn sẽ phải chạy qua mọi mục nhập và kiểm tra xem nó có khác với "Cohen" hay không.
Vì vậy, khi bạn đang tìm kiếm giá trị cụ thể, có vẻ như chỉ dành cho nó. Và khi bạn đang sử dụng NOT, nó sẽ tìm bất kỳ giá trị nào khác có thể vừa với bên trong tinyint(1) (vì tôi hiểu nó không chỉ là 1 hoặc 0, phải không?).

+0

Tôi nghĩ rằng họ chỉ ra trong câu hỏi rằng 'WHERE cancel' cũng không sử dụng chỉ mục. Mặc dù không rõ ràng những gì "Cùng một kết quả" đề cập đến. –

+0

Tôi nghĩ, 'WHERE cancel' là đúng khi giá trị' bị hủy' là 1, 2 hoặc 3 ... Vì vậy, nó vẫn không phải là giá trị ** cụ thể ** vị ngữ –

+0

Bỏ qua thực tế là cột được khai báo là 'tinyint (1)' cùng một tính không đặc trưng sẽ là trường hợp của 'WHERE cancel = true'. –

3

Mặc dù nó sử dụng một chỉ số, chỉ số (tin hay không) có thể thực hiện truy vấn của bạn chậm hơn. Đó là một chút lạ, nhưng nó liên quan đến chỉ số chọn lọc. Nó thường được trình bày trong các cột kiểu boolean.

Nó descrbed như:..

"Làm thế nào giá trị khác nhau của một trường là Nó là một số từ 0-1, mặc dù bạn cũng có thể nghĩ về nó như một tỷ lệ phần trăm Một giá trị của 1 hoặc 100%, có nghĩa là mỗi giá trị trong lĩnh vực này là duy nhất"

Điều quan trọng là phải xem xét becouse:

"MySQL có trình tối ưu hóa dựa trên chi phí. Điều này có nghĩa là MySQL tính toán chi phí các cách thực hiện truy vấn khác nhau và sau đó chọn giá rẻ nhất. Vâng, tính toán chi phí là một khoa học không chính xác. Vì vậy, ước tính được thực hiện, và ước tính là sai đôi khi "

Plain đơn giản:.

Nếu dữ liệu bạn đang tìm kiếm có nhiều hơn hoặc ít hơn 20% giá trị tương tự (ví dụ , hủy có 40% số bàn của bạn) sau đó, nó đơn giản chỉ cần làm một bảng quét

EDIT:.

về câu hỏi của bạn, giải thích cho bạn biết rằng MySQL được usin g một chỉ mục. Tuy nhiên, nó có thể không tốt, cách duy nhất để lưu ý cho dù tối ưu hóa của bạn là tốt hơn là để kiểm tra hiệu suất. Ngoài ra, hãy xem xét costo của các hoạt động INSERT, UPDATE và DELETE để giữ chỉ mục đó. Làm một số hồ sơ có và không có chỉ mục.

Hãy xem này:

+0

Cảm ơn câu trả lời của bạn. Tôi hiểu điều đó bây giờ. Bất kể, câu hỏi vẫn còn. làm thế nào đến "KHÔNG var1" khác với "var1 = false"? – Phoenix

+0

Bạn nói đúng, xin lỗi. Tôi đã chỉnh sửa câu trả lời. – santiagobasulto

1
SELECT * 
FROM 
(SELECT 1 AS C, 0 AS X UNION ALL 
SELECT 2 AS C, 1 AS X UNION ALL 
SELECT 3 AS C, 2 AS X) T 
WHERE X=true 

Returns

'2', '1' 

SELECT * 
FROM 
(SELECT 1 AS C, 0 AS X UNION ALL 
SELECT 2 AS C, 1 AS X UNION ALL 
SELECT 3 AS C, 2 AS X) T 
WHERE X 

Returns

'2', '1' 
'3', '2' 

Vì vậy, có vẻ như rằng trong trường hợp đầu tiên trên true được đúc để int và sau đó được sử dụng trong một vị từ có thể tìm kiếm trong khi trong trường hợp thứ hai giá trị cột được ngầm đúc. Implicit phôi thường làm cho một điều kiện unsargable.

Nhìn vào kế hoạch giải thích cho truy vấn của bạn với WHERE canceled = true cho

+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows |   Extra   | 
+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+ 
| 1 | SIMPLE  | reservations | ref | canceled  | canceled |  1 | const | 1 | Using where; Using filesort | 
+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+ 

Trong khi cho WHERE canceled bạn nhận được

+----+-------------+--------------+------+---------------+-----+---------+-----+------+-----------------------------+ 
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows |   Extra   | 
+----+-------------+--------------+------+---------------+-----+---------+-----+------+-----------------------------+ 
| 1 | SIMPLE  | reservations | ALL |    |  |   |  | 2 | Using where; Using filesort | 
+----+-------------+--------------+------+---------------+-----+---------+-----+------+-----------------------------+ 

Vì vậy, có vẻ như nó thậm chí không thể xem xét các chỉ mục trên canceled như một tùy chọn có thể trong trường hợp này.