2009-02-20 41 views
23

Cho phép nói rằng tôi có một bảng nhiều-nhiều đơn giản giữa các bảng "table1" và "table2" bao gồm từ hai trường int: "table1-id" và "table2-id". Làm thế nào tôi nên lập chỉ mục bảng liên kết này?Làm thế nào để chỉ mục đúng cách một bảng liên kết cho kết nối nhiều-nhiều trong MySQL?

Tôi đã từng tạo chỉ mục tổng hợp chính (table1-id, table2-id), nhưng tôi đã đọc rằng chỉ mục này có thể không hoạt động nếu bạn thay đổi thứ tự của các trường trong truy vấn. Vậy thì giải pháp tối ưu nào sau đó - tạo các chỉ mục độc lập cho từng trường mà không có chỉ mục chính?

Cảm ơn.

Trả lời

25

Tùy thuộc vào cách bạn tìm kiếm.

Nếu bạn tìm kiếm như thế này:

/* Given a value from table1, find all related values from table2 */ 
SELECT * 
FROM table1 t1 
JOIN table_table tt ON (tt.table_1 = t1.id) 
JOIN table2 t2 ON (t2.id = tt.table_2) 
WHERE t1.id = @id 

sau đó bạn cần:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_1, table_2) 

Trong trường hợp này, table1 sẽ được dẫn trong NESTED LOOPS và chỉ số của bạn sẽ được sử dụng chỉ khi table1 được lập chỉ mục đầu tiên .

Nếu bạn tìm kiếm như thế này:

/* Given a value from table2, find all related values from table1 */ 
SELECT * 
FROM table2 t2 
JOIN table_table tt ON (tt.table_2 = t2.id) 
JOIN table1 t1 ON (t1.id = tt.table_1) 
WHERE t2.id = @id 

sau đó bạn cần:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 (table_2, table_1) 

vì những lý do trên.

Bạn không cần chỉ số độc lập ở đây. Chỉ số tổng hợp có thể được sử dụng ở mọi nơi có thể sử dụng chỉ mục đơn giản trên cột đầu tiên. Nếu bạn sử dụng các chỉ số độc lập, bạn sẽ không thể tìm kiếm một cách hiệu quả cho cả hai giá trị:

/* Check if relationship exists between two given values */ 
SELECT 1 
FROM table_table 
WHERE table_1 = @id1 
    AND table_2 = @id2 

Đối với một truy vấn như thế này, bạn sẽ cần ít nhất một chỉ số trên cả hai cột.

Không bao giờ là xấu để có một chỉ số bổ sung cho lĩnh vực thứ hai:

ALTER TABLE table_table ADD CONSTRAINT pk_table1_table2 PRIMARY KEY (table_1, table_2) 
CREATE INDEX ix_table2 ON table_table (table_2) 

Tiểu học trọng điểm sẽ được sử dụng cho các tìm kiếm on both values và cho các tìm kiếm dựa trên giá trị của table_1, chỉ số bổ sung sẽ được sử dụng cho các tìm kiếm dựa trên giá trị của table_2.

+0

Cảm ơn câu trả lời chi tiết, nhưng nếu tôi tìm kiếm cả hai cách thì sao? Ngoài ra tôi đang sử dụng Hibernate vì vậy tôi thậm chí không chắc chắn cách mà nó được sử dụng. – serg

+2

Nếu bạn tìm kiếm cả hai cách, bạn sẽ cần HAI chỉ mục: một tổng hợp cho khóa CHÍNH và một đồng bằng cho cột thứ hai trong khóa CHÍNH. Nó ở cuối bài viết của tôi. – Quassnoi

+0

Cảm ơn câu trả lời tuyệt vời cho chi tiết –

4

Chừng nào bạn đang xác định cả hai phím trong truy vấn, nó không có vấn đề gì để họ có trong truy vấn, nó cũng không phải vấn đề gì để bạn xác định chúng trong chỉ mục.

Tuy nhiên, nó không chắc rằng đôi khi bạn sẽ chỉ có một hay cách khác trong những chìa khóa. Nếu bạn đôi khi chỉ có id_1, thì đó sẽ là lần đầu tiên (nhưng bạn vẫn chỉ cần một chỉ mục).

Nếu đôi khi bạn có, đôi khi bạn có một, đôi khi cả hai, bạn sẽ cần một chỉ mục với cả hai khóa và chỉ mục thứ hai (không duy nhất) với một trường - chọn lọc nhiều hơn hai khóa - và chỉ số tổng hợp chính sẽ bắt đầu bằng khóa khác.

+0

Tôi thích câu trả lời của bạn là tốt nhất nhưng không có chuyên môn để xác minh nó. – jpierson

+0

Bạn có ý nghĩa gì khi 'chọn lọc hơn'? –

+2

Một từ kỹ thuật hơn là "cardinality". Nó có nghĩa là có bao nhiêu giá trị khác nhau cho trường. Tại một cực đoan, cardinality cao, mọi giá trị là duy nhất. Mặt khác, một số trường có thể chỉ có một vài giá trị riêng biệt, trong trường hợp đó một chỉ mục không tiết kiệm nhiều trong cách đọc đĩa. – dkretz

0

@Quassnoi, trong truy vấn đầu tiên của bạn, bạn thực sự chỉ sử dụng khóa tt.table_1 như chúng ta có thể thấy từ mệnh đề WHERE: WHERE t1.id = @id. Và trong truy vấn thứ hai - chỉ tt.table_2.

Vì vậy, chỉ mục nhiều cột có thể chỉ hữu ích trong truy vấn thứ ba do WHERE table_1 = @id1 AND table_2 = @id2. Nếu các truy vấn thuộc loại này sẽ không được sử dụng, bạn có nghĩ rằng nó có giá trị để sử dụng hai chỉ mục một cột riêng biệt thay thế không?

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