2009-04-28 33 views
34

Tôi đã có (ví dụ) một chỉ số:Chỉ mục nhiều cột có hoạt động đối với các lựa chọn cột đơn không?

CREATE INDEX someIndex ON orders (customer, date); 

Liệu chỉ số này chỉ tăng tốc truy vấn mà khách hàng và ngày được sử dụng hay nó tăng tốc truy vấn cho một đơn cột như thế này à?

SELECT * FROM orders WHERE customer > 33; 

Tôi đang sử dụng SQLite.


Nếu câu trả lời là có, tại sao có thể tạo nhiều hơn một chỉ mục cho mỗi bảng?


Một câu hỏi khác: Chỉ số kết hợp nhanh hơn bao nhiêu so với hai chỉ mục phân tách khi bạn sử dụng cả hai cột trong truy vấn?

Trả lời

32

marc_s có câu trả lời đúng cho câu hỏi đầu tiên của bạn. Khóa đầu tiên trong một chỉ mục đa khóa có thể hoạt động giống như một chỉ mục khóa duy nhất nhưng mọi khóa tiếp theo sẽ không hoạt động.

Chỉ số tổng hợp phụ thuộc vào dữ liệu của bạn nhanh hơn như thế nào và cách bạn cấu trúc chỉ mục và truy vấn của mình, nhưng thường là quan trọng. Các chỉ mục về cơ bản cho phép Sqlite thực hiện tìm kiếm nhị phân trên các trường.

Sử dụng ví dụ bạn đưa ra nếu bạn chạy các truy vấn:

SELECT * from orders where customer > 33 && date > 99 

Sqlite đầu tiên sẽ nhận được tất cả kết quả bằng cách sử dụng tìm kiếm nhị phân trên toàn bộ bàn nơi khách hàng> 33. Sau đó, nó sẽ thực hiện tìm kiếm nhị phân chỉ trên những kết quả tìm kiếm ngày> 99.

Nếu bạn đã thực hiện cùng một truy vấn với hai chỉ mục riêng biệt trên khách hàng và ngày, Sqlite sẽ phải tìm kiếm toàn bộ bảng hai lần, trước tiên cho khách hàng và một lần nữa cho ngày đó.

Vì vậy, mức tăng tốc độ bạn sẽ thấy phụ thuộc vào cách bạn cấu trúc chỉ mục của mình liên quan đến truy vấn của bạn. Lý tưởng nhất, trường đầu tiên trong chỉ mục của bạn và truy vấn của bạn phải là trường giúp loại bỏ các kết quả phù hợp nhất có thể để tăng tốc độ lớn nhất bằng cách giảm đáng kể lượng công việc mà tìm kiếm thứ hai phải làm.

Để biết thêm thông tin, xem này: http://www.sqlite.org/optoverview.html

+2

SQLite sẽ KHÔNG sử dụng cột thứ hai của chỉ mục nếu cột đầu tiên là biểu thức bất bình đẳng (ví dụ: khách hàng> 33). (hầu hết các công cụ cơ sở dữ liệu sẽ, khó khăn). – vmatyi

+1

Nếu bạn tạo hai chỉ mục riêng biệt, chỉ một trong số chúng sẽ được sử dụng, biểu thức khác sẽ được đánh giá trên tập kết quả được tạo bởi lần đầu tiên. (trên một Oracle, nó _could_ thực hiện tìm kiếm hai chỉ mục và giao cắt các tập kết quả, nếu tối ưu hóa dựa trên chi phí và các tiêu chí nhất định đáp ứng, nhưng đó là một trường hợp hiếm hoi). – vmatyi

5

Tôi khá chắc chắn điều này sẽ hoạt động, có - nó hiện trong MS SQL Server anyway.

Tuy nhiên, chỉ mục này không giúp bạn nếu bạn chỉ cần chọn ngày tháng, ví dụ: phạm vi ngày. Trong trường hợp đó, bạn có thể cần phải tạo chỉ mục thứ hai chỉ vào ngày để làm cho các truy vấn đó hiệu quả hơn.

Marc

+0

Cảm ơn, đó là nơi tôi không chắc chắn. Tôi sẽ tạo hai chỉ mục riêng biệt trong trường hợp đó. –

3

Tôi thường sử dụng các chỉ số để sắp xếp dữ liệu thông qua kết hợp tôi muốn đánh số trang hoặc yêu cầu "streamily".

Giả sử khách hàng có thể thực hiện nhiều đơn đặt hàng .. và khách hàng từ 0 đến 11 tồn tại và có một số đơn đặt hàng cho mỗi khách hàng được chèn theo thứ tự ngẫu nhiên. Tôi muốn sắp xếp truy vấn dựa trên số khách hàng theo sau ngày tháng. Bạn nên sắp xếp trường id cũng là cuối cùng để phân chia bộ nơi khách hàng có một số ngày giống nhau (ngay cả khi điều đó có thể không bao giờ xảy ra).

sqlite> CREATE INDEX customer_asc_date_asc_index_asc ON orders 
      (customer ASC, date ASC, id ASC); 

Nhận trang 1 của một truy vấn được sắp xếp (giới hạn 10 bài):

sqlite> SELECT id, customer, date FROM orders 
      ORDER BY customer ASC, date ASC, id ASC LIMIT 10; 

2653|1|1303828585 
2520|1|1303828713 
2583|1|1303829785 
1828|1|1303830446 
1756|1|1303830540 
1761|1|1303831506 
2442|1|1303831705 
2523|1|1303833761 
2160|1|1303835195 
2645|1|1303837524 

Lấy trang tiếp theo:

sqlite> SELECT id, customer, date FROM orders WHERE 
      (customer = 1 AND date = 1303837524 and id > 2645) OR 
      (customer = 1 AND date > 1303837524) OR 
      (customer > 1) 
      ORDER BY customer ASC, date ASC, id ASC LIMIT 10; 

2515|1|1303837914 
2370|1|1303839573 
1898|1|1303840317 
1546|1|1303842312 
1889|1|1303843243 
2439|1|1303843699 
2167|1|1303849376 
1544|1|1303850494 
2247|1|1303850869 
2108|1|1303853285 

Và vân vân ...

Có các chỉ mục tại chỗ làm giảm quét chỉ mục phía máy chủ khi bạn sử dụng truy vấn OFFSET cùng với LIMIT. Thời gian truy vấn được lâu hơn và các ổ đĩa tìm kiếm khó khăn càng cao bù đắp đi. Sử dụng phương pháp này loại bỏ điều đó.

Sử dụng phương pháp này được thông báo nếu bạn dự định tham gia dữ liệu sau nhưng chỉ cần một tập hợp dữ liệu hạn chế theo yêu cầu. Tham gia vào SUBSELECT như mô tả ở trên để giảm chi phí bộ nhớ cho các bảng lớn.

+0

Điều này cũng giúp loại bỏ thời gian lệnh phía máy chủ không cần thiết ... nếu bạn sử dụng ** datetime (ngày, 'unixepoch', 'localtime') ** thay vì ** date ** làm cột trả về .. nó chắc chắn sẽ bị hạn chế. Tôi tin rằng nó sẽ là anyways - phụ thuộc vào động cơ. – whardier

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