2010-05-13 33 views
12

tôi đang thực hiện các truy vấn sau đâyMySQL: làm thế nào để chỉ số một "OR" khoản

SELECT COUNT(*) 
FROM table 
WHERE field1='value' AND (field2 >= 1000 OR field3 >= 2000) 

Có một chỉ số trên field1 và khác ghép trên field2 & field3.

Tôi thấy MySQL luôn chọn chỉ mục field1 và sau đó thực hiện kết nối bằng hai trường khác khá tệ vì nó cần tham gia 146.000 hàng.

Đề xuất về cách cải thiện điều này? Cảm ơn

(EDIT sau khi thử GIẢI PHÁP ĐỀ XUẤT)

Có trụ sở tại các giải pháp đề xuất tôi đã thấy điều này trên Mysql khi chơi với điều này.

SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1 
UNION SELECT * FROM table WHERE columnB = value2) AS unionTable; 

là chậm hơn rất nhiều so với thực hiện:

SELECT COUNT(*) 
FROM table 
WHERE (columnA = value1 AND columnB = value2) 
     OR (columnA = value1 AND columnC = value3) 

Có hai chỉ số ghép:

index1 (columnA,columnB) 
index2 (columnA,columnC) 

đủ Thú vị là hỏi Mysql để "giải thích" truy vấn nó lấy luôn index1 trên cả hai trường hợp và chỉ số2 không được sử dụng.

Nếu tôi thay đổi các chỉ số để:

index1 (columnB,columnA) 
index2 (columnC,columnA) 

Và truy vấn:

SELECT COUNT(*) 
FROM table 
WHERE (columnB = value2 AND columnA = value1) 
     OR (columnC = value3 AND columnA = value1) 

Sau đó, nó là cách nhanh nhất tôi đã tìm thấy Mysql hoạt động.

Trả lời

17

Cách điển hình để chia nhỏ các vị từ OR là với UNION.

Lưu ý rằng ví dụ của bạn không phù hợp với chỉ mục của bạn. Ngay cả khi bạn bỏ qua field1 từ vị từ, bạn sẽ có field2 >= 1000 OR field3 >= 2000, không thể sử dụng chỉ mục. Nếu bạn có chỉ mục trên (field1, field2)(field1,field3) hoặc field2 hoặc field3 riêng biệt, bạn sẽ nhận được truy vấn hợp lý nhanh.

SELECT COUNT(*) FROM 
(SELECT * FROM table WHERE field1 = 'value' AND field2 >= 1000 
UNION 
SELECT * FROM table WHERE field1 = 'value' AND field3 >= 2000) T 

Lưu ý rằng bạn phải cung cấp bí danh cho bảng dẫn xuất, đó là lý do tại sao truy vấn phụ được đặt tên là T.

Ví dụ thực tế. Tên cột và bảng đã được ẩn danh!

mysql> SELECT COUNT(*) FROM table; 
+----------+ 
| COUNT(*) | 
+----------+ 
| 3059139 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT COUNT(*) FROM table WHERE columnA = value1; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  1068 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT COUNT(*) FROM table WHERE columnB = value2; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  947 | 
+----------+ 
1 row in set (0.00 sec) 

mysql> SELECT COUNT(*) FROM table WHERE columnA = value1 OR columnB = value2; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  1616 | 
+----------+ 
1 row in set (9.92 sec) 

mysql> SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1 
UNION SELECT * FROM table WHERE columnB = value2) T; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  1616 | 
+----------+ 
1 row in set (0.17 sec) 

mysql> SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1 
UNION ALL SELECT * FROM table WHERE columnB = value2) T; 
+----------+ 
| COUNT(*) | 
+----------+ 
|  2015 | 
+----------+ 
1 row in set (0.12 sec) 
+0

Bạn có một lỗi: Bạn đang đếm yếu tố đáp ứng cả hai tiêu chí (trong đó 'field2> = 1000' * và * 'field3> = 2000') hai lần. (Gợi ý: sử dụng một bảng tạm thời;)) – soulmerge

+6

UNION là UNION DISTINCT theo mặc định. Các hàng trùng lặp được xóa như một phần của cấu trúc UNION. Nếu thực sự đếm chúng hai lần, người ta sẽ sử dụng 'UNION ALL'. Bạn thậm chí đã thử tuyên bố tôi đã đề xuất trên một số bảng tương tự của riêng bạn? –

5

Tôi mới ở đây nên tôi không thể nhận xét về bài đăng của người khác nhưng điều này liên quan đến các bài đăng của David M. và soulmerge.

Bảng tạm thời là không cần thiết. UNION David M. đề xuất không tính hai lần, vì UNION ngụ ý một sự khác biệt (tức là nếu một hàng tồn tại trong một nửa của công đoàn, bỏ qua nó trong cái kia). Nếu bạn đã sử dụng UNION ALL, bạn sẽ nhận được hai bản ghi.

Hành vi mặc định cho UNION là các hàng trùng lặp sẽ bị xóa khỏi kết quả.Từ khóa DISTINCT tùy chọn không có tác dụng khác với mặc định vì nó cũng chỉ định loại bỏ hàng trùng lặp. Với từ khóa ALL tùy chọn, việc loại bỏ hàng trùng lặp không xảy ra và kết quả bao gồm tất cả các hàng phù hợp từ tất cả các câu lệnh SELECT.

http://dev.mysql.com/doc/refman/5.0/en/union.html

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