2013-04-15 36 views
7

tôi là hợp lý mới cho MySQL và tôi đang cố gắng để chọn một tập hợp riêng biệt của hàng bằng tuyên bố này:CHỌN tuyên bố DISTINCT trong MySQL đang 10 phút

SELECT DISTINCT sp.atcoCode, sp.name, sp.longitude, sp.latitude 
FROM `transportdata`.stoppoints as sp 
INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code 
INNER JOIN `vehicledata`.gtfstrips as trip ON st.trip_id = trip.trip_id 
INNER JOIN `vehicledata`.gtfsroutes as route ON trip.route_id = route.route_id 
INNER JOIN `vehicledata`.gtfsagencys as agency ON route.agency_id = agency.agency_id 
WHERE agency.agency_id IN (1,2,3,4); 

Tuy nhiên, báo cáo kết quả lựa chọn là dùng khoảng 10 phút, vì vậy một cái gì đó rõ ràng là bắt đầu.

Một yếu tố quan trọng là bảng gtfsstop_times là rất lớn. (~ 250 triệu bản ghi)

Các chỉ mục dường như được thiết lập đúng cách; tất cả các phép nối trên đều sử dụng các cột được lập chỉ mục. Kích thước bảng là, khoảng:

gtfsagencys - 4 rows 
gtfsroutes - 56,000 rows 
gtfstrips - 5,500,000 rows 
gtfsstop_times - 250,000,000 rows 
`transportdata`.stoppoints - 400,000 rows 

Máy chủ có 22Gb bộ nhớ, tôi đã đặt nhóm đệm InnoDB thành 8G và tôi đang sử dụng MySQL 5.6.

Ai có thể xem cách làm cho hoạt động này chạy nhanh hơn không? Hoặc thực sự, ở tất cả!

Có vấn đề gì khi bảng điểm dừng trong một lược đồ khác?

EDIT: GIẢI THÍCH SELECT ... trả về này:

enter image description here

+2

Điều này thực hiện như thế nào nếu bạn bỏ qua vòng loại 'DISTINCT'? Bạn nhận được gì khi sử dụng 'GIẢI THÍCH' trên truy vấn? –

+3

Kế hoạch giải thích là gì? Dán nó vào pastebin hoặc một gist –

+1

Tôi không chắc chắn làm thế nào tôi sẽ kiểm tra rằng, vì nếu tôi bỏ qua vòng loại thì khoảng 250 triệu hàng sẽ được trả về. Xin lỗi nếu điều này có vẻ như vô nghĩa, tôi là một chút mới để thử nghiệm/gỡ lỗi truy vấn. –

Trả lời

6

Có vẻ như bạn đang cố gắng tìm một tập hợp các điểm dừng, dựa trên các tiêu chí nhất định. Và, bạn đang sử dụng SELECT DISTINCT để tránh các điểm dừng trùng lặp. Có đúng không?

Dường như atcoCode là khóa duy nhất cho bảng điểm của bạn. Có đúng không?

Nếu vậy, hãy thử này:

SELECT sp.name, sp.longitude, sp.latitude, sp.atcoCode 
    FROM `transportdata`.stoppoints` AS sp 
    JOIN ( 
    SELECT DISTINCT st.fk_atco_code AS atcoCode 
     FROM `vehicledata`.gtfsroutes AS route 
     JOIN `vehicledata`.gtfstrips AS trip ON trip.route_id = route.route_id 
     JOIN `vehicledata`.gtfsstop_times AS st ON trip.trip_id = st.trip_id 
     WHERE route.agency_id BETWEEN 1 AND 4 
) ids ON sp.atcoCode = ids.atcoCode 

này thực hiện một vài điều: Nó giúp loại bỏ một bảng (cơ quan) mà bạn dường như không cần. Nó thay đổi tìm kiếm trên agency_id từ IN(a,b,c) thành tìm kiếm theo phạm vi, có thể có hoặc không thể trợ giúp. Và cuối cùng nó di chuyển việc xử lý DISTINCT từ một tình huống mà nó phải xử lý toàn bộ tấn dữ liệu cho một tình huống truy vấn con nơi nó chỉ phải xử lý các giá trị ID.

(JOININNER JOIN đều giống nhau. Tôi đã từng JOIN để làm cho truy vấn dễ dàng hơn một chút để đọc.)

này cần đẩy bạn lên một chút. Nhưng, nó phải được nói, một bảng gigarow quý là một bảng lớn.

+0

+1 để suy nghĩ về SQL thực tế và phát hiện những tối ưu hóa đó. Tôi thậm chí không biết rằng bạn có thể sử dụng 'JOIN (SELECT ...)' làm cú pháp hợp lệ. Điều này đã cắt giảm thời gian truy vấn của tôi một nửa, cảm ơn bạn. Chỉ cần kiểm tra câu trả lời được đề xuất khác. –

+0

Điều này thực sự là một tối ưu hóa đáng kể trên những gì tôi đã có, nhờ câu trả lời tuyệt vời. –

+0

Nhân tiện, @Carlos P, để lại bất cứ thứ gì bạn không cần trong danh sách các cột bạn 'SELECT'. Bạn có thực sự sử dụng giá trị 'name' và' atcoCode' trong ứng dụng của mình không? Nếu không, đừng hỏi họ: tập hợp kết quả này là một phần ba của megarow hoặc hơn, và phải mất thời gian để trộn nhiều dữ liệu từ máy chủ đến máy khách. –

3

Có 250M hồ sơ, tôi sẽ Shard bảng gtfsstop_times trên một cột. Sau đó, mỗi bảng phân đoạn có thể được nối trong một truy vấn riêng biệt có thể chạy song song trong các luồng riêng biệt, bạn sẽ chỉ cần hợp nhất các tập kết quả.

+0

Bạn có thể giải thích thêm một chút trong câu trả lời của bạn những gì bạn có nghĩa là "sharding"? Cảm ơn. – Jocelyn

+0

Anh ấy có nghĩa là http://xeround.com/blog/2011/11/mysql-sharding-vs-mysql-partitioning này và tại đây http://en.wikipedia.org/wiki/Shard_(database_architecture) –

+0

Ngoài sự tò mò, làm thế nào điều này sẽ làm việc? Việc hợp nhất các tập kết quả không tự nó tốn thời gian như công việc ban đầu, vì chúng ta đang tìm kiếm các mục riêng biệt? –

2

Bí quyết là giảm số lượng hàng gtfsstop_times SQL phải đánh giá. Trong trường hợp này, SQL đầu tiên đánh giá mọi hàng trong kết nối bên trong của gtfsstop_timestransportdata .stoppoints, phải không? Có bao nhiêu hàng transportdata .stoppoints có? Sau đó SQL đánh giá mệnh đề WHERE, sau đó nó đánh giá DISTINCT. Làm thế nào để nó DISTINCT? Bằng cách xem xét mọi hàng đơn lẻ nhiều lần để xác định xem có các hàng khác như nó hay không. Điều đó sẽ mất mãi mãi, phải không?

Tuy nhiên, GROUP BY nhanh chóng thu thập tất cả các hàng phù hợp với nhau mà không đánh giá từng hàng. Tôi thường sử dụng các phép nối để nhanh chóng giảm số hàng mà truy vấn cần đánh giá, sau đó tôi xem nhóm của mình.

Trong trường hợp này, bạn muốn thay thế DISTINCT bằng cách nhóm.

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

SELECT sp.name, sp.longitude, sp.latitude, sp.atcoCode 

FROM `transportdata`.stoppoints as sp 
    INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code 
    INNER JOIN `vehicledata`.gtfstrips as trip ON st.trip_id = trip.trip_id 
    INNER JOIN `vehicledata`.gtfsroutes as route ON trip.route_id = route.route_id 
    INNER JOIN `vehicledata`.gtfsagencys as agency ON route.agency_id = agency.agency_id 

WHERE agency.agency_id IN (1,2,3,4) 

GROUP BY sp.name 
    , sp.longitude 
    , sp.latitude 
    , sp.atcoCode 
+0

Cảm ơn, tôi đã thử điều này nhưng nó thực sự * tăng * thời gian truy vấn. Tôi đã thử nó với một truy vấn nhỏ hơn nhiều ('WHERE agency.agency_id = 1') thường mất 4-5 giây và mất khoảng 8 giây. 'sp.name',' sp.longitude', 'sp.latitude' không được lập chỉ mục, đó có phải là lý do không? Tôi không chắc chắn tôi hiểu được logic để nhóm theo tất cả bốn cột này; điều này là cần thiết và, nếu có, tôi có nên lập chỉ mục tất cả? Tôi lo lắng rằng việc thực hiện đánh chỉ mục tất cả chúng có thể lớn hơn lợi ích. –

+0

Theo ý kiến ​​của bạn, cách làm này tốt hơn câu trả lời của @Ollie Jones, vì đề xuất của anh ấy dường như hoạt động nhanh hơn rất nhiều. –

+0

Tôi cũng có thể thêm rằng tôi đã thực hiện một lỗi trong câu hỏi của tôi, cột DISTINCT là sp.atcoCode - điều này có thể giải thích sự bất thường? –

1

Có câu trả lời có giá trị khác cho câu hỏi của bạn và của tôi là bổ sung cho nó. Tôi giả sử sp.atcoCodest.fk_atco_code là các cột được lập chỉ mục trong bảng của chúng.

Nếu bạn có thể xác thực và đảm bảo rằng id đại lý trong mệnh đề WHERE hợp lệ, bạn có thể loại trừ tham gia `vehicledata .gtfsagencys` trong JOINS vì bạn không tìm nạp bất kỳ bản ghi nào từ bảng.

SELECT DISTINCT sp.atcoCode, sp.name, sp.longitude, sp.latitude 
FROM `transportdata`.stoppoints as sp 
INNER JOIN `vehicledata`.gtfsstop_times as st ON sp.atcoCode = st.fk_atco_code 
INNER JOIN `vehicledata`.gtfstrips as trip ON st.trip_id = trip.trip_id 
INNER JOIN `vehicledata`.gtfsroutes as route ON trip.route_id = route.route_id 
WHERE route.agency_id IN (1,2,3,4); 
+0

Cảm ơn, mặc dù tôi tin rằng @Ollie Jones đã phát hiện ra điều này? Đánh giá cao câu trả lời mặc dù. –

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