2013-07-23 41 views
6

Trên một bảng Innodb đơn giản nhưng rất lớn, tôi có một chỉ mục duy nhất trên cột A và tôi muốn nhận danh sách cột (số nguyên) B theo thứ tự cột (số nguyên) ATại sao MySQL Innodb "Tạo chỉ mục sắp xếp" khi chỉ mục duy nhất tồn tại?

Truy vấn rất đơn giản, tôi phân trang qua hàng triệu bản ghi.

SELECT B FROM hugeTable ORDER BY A LIMIT 10000 OFFSET 500000

Mất 10 giây cho mỗi truy vấn trên một máy chủ rất nhanh?

Filesort: Yes Filesort_on_disk: Yes Merge_passes: 9

Điều này làm cho không có ý nghĩa với tôi, tại sao nó không thể sử dụng Index A?

Giải thích cho thấy đơn giản, không có khóa và tệp có thể.

Trả lời

10

Nếu các giá trị cho cột B không có sẵn trong các trang chỉ mục, thì MySQL sẽ cần phải truy cập các trang trong bảng bên dưới. Cũng không có biến vị ngữ nào lọc các hàng đang được xem xét, và điều đó có nghĩa là MySQL đang thấy rằng tất cả các hàng cần được trả về. Điều này có thể giải thích tại sao chỉ số này không được sử dụng.

Cũng lưu ý rằng các hoạt động LIMIT được xử lý ở cuối báo cáo, gần như là bước cuối cùng trong kế hoạch thực hiện, với một số ngoại lệ.

8.2.1.3. Optimizing LIMIT Queries http://dev.mysql.com/doc/refman/5.5/en/limit-optimization.html

Tôi nghi ngờ rằng câu hỏi của bạn có thể làm cho việc sử dụng một chỉ số bao phủ, ví dụ như "ON hugetable (A,B)", để tránh các hoạt động phân loại.

Không có chỉ mục bao gồm, bạn có thể thử viết lại truy vấn như thế này, để xem điều này sẽ sử dụng chỉ mục trên cột A hay không và tránh hoạt động sắp xếp trên hàng triệu hàng (để nhận 510.000 hàng đầu tiên theo thứ tự):

SELECT i.B 
    FROM (SELECT j.A 
      FROM hugeTable j 
      ORDER 
      BY j.A 
      LIMIT 10000 OFFSET 500000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
ORDER 
    BY k.A 

tôi đề nghị bạn làm một EXPLAIN trên chỉ truy vấn xem inline (bí danh như k), và xem nếu nó cho thấy "Using index."

Truy vấn bên ngoài có thể vẫn còn hoạt động "Using filesort", nhưng ít nhất nó sẽ chỉ có trên 10.000 hàng.

(Chú ý: Bạn có thể muốn thử một "ORDER BY i.A" thay cho "k.A" trên truy vấn bên ngoài, và xem nếu mà làm cho một sự khác biệt.)


PHỤ LỤC

Không giải quyết cụ thể câu hỏi của bạn, nhưng về hiệu suất của truy vấn đó, nếu điều này là "phân trang qua" một tập hợp các hàng, một tùy chọn khác để xem xét, để đến trang "tiếp theo" là sử dụng giá trị "A" từ hàng cuối cùng được truy lục trên truy vấn trước đó dưới dạng "điểm bắt đầu" cho t anh ấy hàng tiếp theo.

Truy vấn ban đầu có vẻ như đang nhận được "trang 51" (10.000 hàng trên mỗi trang, trang 51 sẽ là các hàng từ 510.001 đến 520.000).

Nếu bạn cũng trả lại giá trị của 'A' và giữ nguyên giá trị đó cho hàng cuối cùng.Để có được trang "tiếp theo", truy vấn có thể thực sự là:

SELECT i.B, k.A 
    FROM (SELECT j.A 
      FROM hugeTable j 
      WHERE j.A > $value_of_A_from_row_520000 
     -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
      LIMIT 10000 
     ) k 
    JOIN hugetable i 
    ON i.A = k.A 
    ORDER 
    BY k.A 

Nếu bạn cũng giữ giá trị cho A từ hàng "đầu tiên", bạn có thể sử dụng để sao lưu trang. Điều đó thực sự sẽ chỉ hoạt động để chuyển tiếp một trang hoặc quay lại một trang. Chuyển sang một trang khác, sẽ phải sử dụng dạng truy vấn gốc, đếm các hàng.

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