2009-08-07 35 views
5

Tôi có một bảng lớn (TokenFrequency) có hàng triệu hàng trong đó. Bảng TokenFrequency được cấu trúc như thế này:SQL Thay thế để thực hiện INNER JOIN trên một bảng đơn

Bảng - TokenFrequency

  • id - int, khóa chính
  • nguồn - int, ngoại chủ chốt
  • thẻ - char
  • đếm - int

Mục tiêu của tôi là chọn tất cả các hàng trong đó hai nguồn có cùng mã thông báo trong đó. Ví dụ: nếu bảng của tôi trông như thế này:

id --- nguồn --- mã thông báo --- đếm
1 ------ 1 --------- dog - ----- 1
2 ------ 2 --------- cat -------- 2
3 ------ 3 ----- ---- cat -------- 2
4 ------ 4 --------- lợn -------- 5
5 ---- - 5 --------- sở thú ------- 1
6 ------ 5 --------- cat -------- 1
7 ------ 5 --------- lợn -------- 1

Tôi muốn một truy vấn SQL cung cấp cho tôi nguồn 1, nguồn 2 và tổng số đếm. Ví dụ:

source1 --- source2 --- thẻ --- đếm
---- 2 ----------- 3 --------- mèo -------- 4
---- 2 ----------- 5 --------- cat -------- 3
---- 3 ----------- 5 --------- cat -------- 3
---- 4 ------- ---- 5 --------- -------- lợn 6

tôi có một truy vấn mà trông như thế này:

SELECT F.source AS source1, S.source AS source2, F.token, 
     (F.count + S.count) AS sum 
FROM  TokenFrequency F 
INNER JOIN TokenFrequency S ON F.token = S.token 
WHERE F.source <> S.source 

Truy vấn này hoạt động tốt nhưng những vấn đề mà tôi có với nó là rằng:

  1. Tôi có một bảng TokenFrequency rằng có hàng triệu hàng và do đó cần một sự thay thế nhanh hơn để có được kết quả này.
  2. Truy vấn hiện tại tôi đang cung cấp cho các bản sao. Ví dụ: lựa chọn của nó:
    source1 = 2, source2 = 3, token = cat, count = 4
    source1 = 3, source2 = 2, token = cat, count = 4
    Đó không phải là quá nhiều của một vấn đề nhưng nếu có một cách để thu hút những người đó và lần lượt có được sự gia tăng tốc độ thì sẽ rất hữu ích

Vấn đề chính mà tôi có là tốc độ truy vấn hiện tại của tôi phải mất hàng giờ để hoàn thành. INNER JOIN trên một bảng để chính nó là những gì tôi tin là vấn đề. Im chắc chắn phải có một cách để loại bỏ phép nối bên trong và nhận được các kết quả tương tự chỉ bằng một cá thể của bảng TokenFrequency. Vấn đề thứ hai mà tôi đã đề cập cũng có thể thúc đẩy tăng tốc độ truy vấn.

Tôi cần một cách để cơ cấu lại truy vấn này để cung cấp cùng một kết quả theo cách nhanh hơn, hiệu quả hơn.

Cảm ơn.

+1

Bạn có thể đăng GIẢI THÍCH truy vấn (http://dev.mysql.com/doc/refman/5.0/en/explain.html) hay không. Nó sẽ giúp mọi người thấy cách họ có thể giúp bạn tối ưu hóa. –

+0

bạn cần cung cấp một số thông tin chỉ mục, cột nào, v.v. –

+0

Đây là GIẢI THÍCH của truy vấn mà tôi đã đăng lần đầu. id: 1, select_type: SIMPLE, bảng: F & S, nhập: ALL, Possible_keys: NULL, Khoá: NULL, Key_len: NULL, ref: NULL, hàng: 8, Thêm: Sử dụng vị trí; Sử dụng bộ đệm nối Có hai hàng trả về sự khác biệt duy nhất là hai tên bảng F và S. – cruzja

Trả lời

2

tôi cần một chút biết thêm để chẩn đoán các vấn đề tốc độ, nhưng để loại bỏ các dups, thêm video này vào WHERE:

AND F.source<S.source 
+0

Ah rất đơn giản. Điều này làm việc hoàn hảo để loại bỏ các bản sao. Cảm ơn – cruzja

2

Hãy thử điều này:

SELECT token, GROUP_CONCAT(source), SUM(count) 
FROM TokenFrequency 
GROUP BY token; 

này nên chạy nhanh hơn rất nhiều và cũng loại bỏ các bản sao. Nhưng các nguồn sẽ được trả về trong danh sách được phân cách bằng dấu phẩy, vì vậy bạn sẽ phải phát nổ trong ứng dụng của mình.

Bạn cũng có thể thử tạo chỉ mục phức hợp trên các cột token, source, count (theo thứ tự đó) và phân tích với EXPLAIN để xem liệu MySQL có đủ thông minh để sử dụng nó như là một covering index cho truy vấn này không.


Cập nhật: Tôi dường như đã hiểu nhầm câu hỏi của bạn. Bạn không muốn tổng số tiền trên mỗi mã thông báo, bạn muốn tổng số tiền cho mỗi cặp nguồn cho một mã thông báo đã cho.

Tôi tin rằng tham gia bên trong là giải pháp tốt nhất cho việc này. Một hướng dẫn quan trọng cho SQL là nếu bạn cần tính toán một biểu thức liên quan đến hai hàng khác nhau, thì bạn cần phải thực hiện một phép nối.

Tuy nhiên, một kỹ thuật tối ưu hóa mà tôi đã đề cập ở trên là sử dụng bao gồm chỉ mục để tất cả các cột bạn cần được bao gồm trong cấu trúc dữ liệu chỉ mục. Lợi ích là tất cả các tra cứu của bạn là O (log n) và truy vấn không cần phải thực hiện một I/O thứ hai để đọc hàng vật lý để nhận các cột khác.

Trong trường hợp này, bạn nên tạo chỉ mục bao phủ trên các cột token, source, count như tôi đã đề cập ở trên. Cũng cố gắng phân bổ đủ không gian bộ nhớ cache để chỉ mục có thể được lưu trữ trong bộ nhớ.

+1

+1 cho cách tiếp cận phù hợp; nhưng một chỉ mục như vậy sẽ gần như lớn như toàn bộ hồ sơ, bạn có nghĩ rằng nó sẽ nhanh hơn chỉ là lập chỉ mục trên mã thông báo không? – Javier

+0

Phụ thuộc vào số hàng và các yếu tố cụ thể của hệ thống khác. Cách duy nhất để chắc chắn là thử nó với cơ sở dữ liệu * của bạn * và đo hiệu suất. –

+0

Đây là một cách tiếp cận tốt nhưng vấn đề duy nhất mà nó tạo ra nếu bạn có một mã thông báo có nhiều hơn một nguồn thì bạn sẽ nhận được tất cả các trường hợp được thêm vào với nhau.Ví dụ trong trường hợp ví dụ của tôi, mã thông báo "cat" nằm trong nguồn 2,3 và 5 vì vậy nó cho tôi số lượng 5 thay vì cho tôi 2 & 3 với số lượng là 4, 3 & 5 với số lượng là 3 và 2 & 5 với đếm 3. Trong bộ dữ liệu lớn, thực sự của tôi, có các mã thông báo xuất hiện trong hầu hết mọi tài liệu sẽ cung cấp cho tôi GROUP_CONCAT nghìn nguồn và số lượng sự tôn trọng của chúng. – cruzja

1

Nếu mã thông báo không được lập chỉ mục, nó chắc chắn phải như vậy.

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