2013-07-28 28 views
5

Tôi đang làm việc trên một ứng dụng lấy dữ liệu từ nhiều nguồn khác nhau và tạo báo cáo. Hiện tại tôi đang thay đổi nó để thực hiện các báo cáo dựa trên dữ liệu từ một ngày cụ thể trong lịch sử, trước đây nó chỉ hiển thị dữ liệu từ trạng thái hiện tại.BugZilla, cách tốt nhất (nhanh nhất) để nhận trạng thái lỗi (v.v) vào một ngày cụ thể

Một trong những nguồn dữ liệu của tôi là Bugzilla, vì vậy tôi cần lấy dữ liệu Bugzilla cho một ngày nhất định trong lịch sử. Tôi có một kết nối chỉ đọc vào cơ sở dữ liệu Bugzilla nhưng không có cách nào dễ dàng để làm bất cứ điều gì khác với máy chủ (như cài đặt plug-in, hoặc đặt thủ tục trong cơ sở dữ liệu). Ngoài ra, kết nối giữa máy chủ báo cáo và máy chủ Bugzilla chậm, vì vậy tôi muốn thực hiện các phép tính trên máy chủ thay vì tìm nạp dữ liệu và làm việc trên máy chủ báo cáo. Tôi thực sự có điều này làm việc ở một tốc độ chủ yếu chấp nhận được, nhưng tôi không chắc chắn nếu tôi đang làm nó tốt nhất hay 'đúng', tôi lo ngại rằng tốc độ có thể chấm dứt được chấp nhận khi chúng tôi thêm nhiều vấn đề hơn với cơ sở dữ liệu.

Vì vậy, giải pháp của tôi dưới đây - bạn sẽ làm như thế nào.

Đối với một chút nền, Bugzilla lưu trữ trạng thái hiện tại của tất cả các lỗi trong bảng (gọi là 'lỗi') và lịch sử thay đổi cho từng trường trong bảng ('bugs_activity') trông giống như sau:

fieldid INTEGER, -- References the fielddefs table 
bug_when TIMESTAMP, -- Time the change happend 
added  TEXT,  -- New text for the field 
removed TEXT,  -- Old text for the field 

Cơ sở dữ liệu Bugzilla là MySQL. Tôi nghĩ rằng đúng cách để làm điều đó là hoặc với một thủ tục lưu trữ hoặc một bảng tạm thời, nhưng tôi không có một trong hai tùy chọn có sẵn cho tôi. Tôi biết cũng có các công cụ báo cáo cho Bugzilla nhưng tôi không có quyền truy cập để cài đặt chúng, cũng là các báo cáo tôi đang tạo dữ liệu liên kết từ các nguồn khác (và có định dạng cụ thể).

Có một cơ sở dữ liệu PostgreSQL cục bộ trên máy chủ báo cáo để tôi có thể định kỳ sao chép tất cả dữ liệu sang đó, nhưng tôi thực sự không muốn làm điều đó vì có vẻ hơi lãng phí khi lưu trữ dữ liệu giống nhau ở hai nơi.

Giải pháp của tôi là tạo bảng trong vùng chọn giống như bảng lỗi thông thường (đối với dữ liệu tôi quan tâm cho một báo cáo nhất định) và sau đó sử dụng tùy chọn này làm nguồn cho lựa chọn bình thường hoạt động giống như truy vấn cho các báo cáo dựa trên dữ liệu ngày nay.

SELECT bug_status, bug_id, op_sys, resolution, rep_platform 
    FROM (SELECT bug_id, 
     IFNULL((SELECT removed FROM bugs_activity a, fielddefs f 
       WHERE a.fieldid = f.id 
        AND bug_id = b.bug_id AND f.name = 'bug_status' 
        AND bug_when >= '2012-01-01 00:00:00' 
       ORDER BY bug_when DESC LIMIT 1), bug_status) AS bug_status, 
    -- Repeat IFNULL clause for op_sys, resolution and rep_platform 
     FROM bugs b 
     WHERE b.creation_ts <= '2012-01-01 00:00:00') bug_subselect 
     -- Some other filters to reduce the bugs (specific product, ect) 
    ) 
    -- More filters based on the new values that have been derived 
    ; 

Sau đó, tôi sử dụng như là một đầu vào một lựa chọn mà đếm các trạng thái khác nhau, vv

Truy vấn này hóa ra là cách quá chậm, tôi giả sử vì nó nhận được kết quả toàn bộ cho bên trong chọn để nó có thể đặt hàng sau đó và cho tôi cái đầu.

Tôi đã thử làm điều đó bằng cách LEFT THAM GIA bảng bug_activity vào bảng lỗi nhiều lần và sau đó thực hiện truy vấn IFNULL trên các kết quả, nhanh nhưng phức tạp một chút để duy trì trong mã thế hệ để điều chỉnh nó thành điều này:

SELECT bug_status, bug_id, op_sys, resolution, rep_platform 
    FROM (SELECT bug_id, 
    IFNULL((SELECT removed FROM bugs_activity a, fielddefs f 
      WHERE a.fieldid = f.id AND bug_id = b.bug_id AND f.name = 'bug_status' 
       AND bug_when = (
        SELECT MIN(bug_when) FROM bugs_activity a, fielddefs f 
         WHERE a.fieldid = f.id 
          AND bug_id = b.bug_id 
          AND f.name = 'bug_status' 
         AND bug_when >= '2012-01-01 00:00:00' 
          LIMIT 1 
         ) 
      LIMIT 1), bug_status) AS bug_status, 
     -- Repeat IFNULL clause for op_sys, resolution and rep_platform 
     FROM bugs b 
     WHERE b.creation_ts <= '2012-01-01 00:00:00') bug_subselect 
     -- Some other filters to reduce the bugs (specific product, ect) 
    ) 
    -- More filters based on the new values that have been derived 
     ; 

Bạn cần cả LIMIT 1 trong đó (tôi nghĩ) như một số lĩnh vực đã quản lý để có hai thay đổi trên timestamp cùng (hoặc một trục trặc cơ sở dữ liệu, có thể từ một bản nâng cấp, hoặc hai người dùng chỉnh sửa các lỗi tương tự - - Tôi không chắc chắn, tôi chỉ biết rằng nó ở đó và tôi cần phải giải quyết nó).

Điều này chạy trong khoảng 3 giây mà không có bộ lọc để giảm danh sách lỗi (trường hợp xấu nhất và hầu như không bao giờ xảy ra) và chạy nhanh hơn với bộ lọc. Phiên bản LEFT JOIN chạy ở cùng tốc độ (hơi chậm hơn) vì vậy tôi đã đi với phiên bản trên.OK cho thời điểm này, nhưng tôi có thể thấy nó chậm trong tương lai - Tôi sẽ thêm thông báo tải trong GUI và đã có thông báo cho biết các báo cáo này có thể mất nhiều thời gian hơn để tạo, tôi chỉ tự hỏi nếu tôi ' m thiếu một số mẹo để làm cho nó nhanh hơn.

+0

"Tôi chỉ tự hỏi nếu tôi thiếu một số thủ thuật để làm cho nó nhanh hơn" - vâng. Chúng được gọi là chỉ mục ... –

+1

Bảng bugs_activity không có chỉ mục, hoặc bạn có ý gì đó khác. – SpaceDog

+0

Tôi có nghĩa là chính xác những gì tôi đã nói - chỉ số tăng tốc truy vấn. –

Trả lời

1

Nếu tôi nhận bạn một cách chính xác bạn có thể thử này ..

SET @tdate = '2012-01-01 00:00:00'; 

SELECT 
    b.bug_id 
    ,CASE 
    WHEN s.removed IS NULL THEN b.bug_status 
    ELSE s.removed 
    END AS statusAtDate 
    ,CASE 
    WHEN o.removed IS NULL THEN b.op_sys 
    ELSE o.removed 
    END AS apSysAtDate 
FROM 
    bugs AS b 
    LEFT OUTER JOIN (
    SELECT 
     a.bug_id 
     ,a.bug_when 
     ,a.removed 
     ,a.bug_when 
     ,@row_num := IF(@last=a.bug_id,@row_num+1,1) AS rnk 
     ,@last:=a.bug_id 
    FROM 
     bug_activity AS a 
     INNER JOIN fielddefs AS f 
     ON a.fieldid = f.id 
      AND f.name = 'bug_status' 
    WHERE 
     a.bug_when <= @tdate 
    ORDER BY 
     a.bug_id 
     ,a.bug_when 
    ) AS s 
     ON b.bug_id = s.bug_id 
     AND s.rnk=1 
    LEFT OUTER JOIN (
    SELECT 
     a.bug_id 
     ,a.bug_when 
     ,a.removed 
     ,a.bug_when 
     ,@row_num := IF(@last=a.bug_id,@row_num+1,1) AS rnk 
     ,@last:=a.bug_id 
    FROM 
     bug_activity AS a 
     INNER JOIN fielddefs AS f 
     ON a.fieldid = f.id 
      AND f.name = 'op_sys' 
    WHERE 
     a.bug_when <= @tdate 
    ORDER BY 
     a.bug_id 
     ,a.bug_when 
    ) AS o 
     ON b.bug_id = o.bug_id 
     AND o.rnk=1 

--repeat for resolution and rep_platform 

xin lỗi tôi không có một db đây để xác minh mã rất tiếc nếu có lỗi chính tả hoặc tương tự ..

Tôi không biết nếu đó là cách bạn đã làm bên ngoài tham gia bên ngoài trước nhưng điều đó giúp/làm việc nếu bạn sử dụng một biến phiên để tái sử dụng?

không chắc chắn liệu điều này có hỗ trợ gì khi bạn nói rằng phương thức kết nối bên ngoài bên trái của bạn đang chạy ở cùng tốc độ.

Tôi không có chuyên gia tối ưu hóa bằng cách (xa nó) .. chỉ cần nói những gì tôi sẽ cố gắng khác hơn là gợi ý tốt để có được một số chỉ mục trên đường đi.

EDIT:

Một điều bạn có thể thử .. Tôi nghĩ này nên làm việc ..

SELECT 
    bug_id 
    ,bug_status 
    ,op_sys 
    ,max(old_status) 
    ,max(old_opSys) 
(
SELECT 
    * 
FROM 
    bugs AS b 
    LEFT OUTER JOIN (
    SELECT 
     a.bug_id 
     ,a.bug_when 
     ,if(f.name = 'bug_status',a.removed,NULL) AS old_status 
     ,if(f.name = 'op_sys',a.removed,NULL) AS old_opSys 
     ,a.bug_when 
     ,@row_num := IF(@last=a.bug_id [email protected]=f.name ,@row_num+1,1) AS rnk 
     ,@last:=a.bug_id 
     ,@lastField:=f.name 
    FROM 
     bug_activity AS a 
     INNER JOIN fielddefs AS f 
     ON a.fieldid = f.id 

    WHERE 
     a.bug_when <= '2012-01-01 00:00:00' 
     AND f.name in('bug_status','op_sys') 
    ORDER BY 
     a.bug_id 
     ,f.name 
     ,a.bug_when 
    ) AS s 
     ON b.bug_id = s.bug_id 
     AND s.rnk=1 
) AS T 
    GROUP BY 
    bug_id 
    ,bug_status 
    ,op_sys 

Tôi đã bỏ qua trường hợp hoặc nếu tuyên bố từ bên ngoài chọn ở đây. Tôi đã suy nghĩ không có vấn đề mà giải pháp nó có thể là giá trị thử nghiệm như thế nào nó chạy làm kiểm tra cuối cùng trong mã chứ không phải là DB? ngay cả khi điều đó làm việc bạn có thể không lựa chọn nó nhưng nó có thể là giá trị kiểm tra.

như trong một cái gì đó như:

<%= row->old_status ?: row->bug_status %> 

(xin lỗi nếu PHP của tôi là tắt .. không thực sự sử dụng nó nhiều)

có vẻ như nó sẽ làm việc? http://sqlfiddle.com/#!2/eff8c/1

+0

bạn có thể làm điều gì đó sôi nổi, nơi bạn tham gia vào bảng hoạt động một lần cho tất cả các trường và thay đổi cột rnk mỗi lần bug_id hoặc tên trường thay đổi. sau đó bọc toàn bộ rất nhiều trong một nhóm bởi bug_id và tối đa trên mỗi cột khác .. không knwo nếu nó sẽ được bất kỳ nhanh hơn và không thể nhớ nếu bạn có thể tối đa các lĩnh vực văn bản như thế trong mysql. – gordatron

+1

Cảm ơn bạn đã dành thời gian trả lời. Đó là một cách tiếp cận thú vị, và tôi sẽ phải khéo léo với nó một chút. Nhưng hiện tại nó chậm hơn khoảng sáu lần so với cách tiếp cận của tôi. Thật thú vị, nếu @tdate là NULL (bởi vì tôi quên để thiết lập nó), nó nhanh hơn nhiều, tôi đoán máy chủ đang làm một số tối ưu hóa thông minh (hoặc vì không có kết quả được trả về trong nội bộ). Tôi sẽ làm một số thử nghiệm và hồ sơ, nó cho tôi một vài con đường để khám phá ít nhất. :) – SpaceDog

+0

Sự khác biệt tốc độ lớn như vậy! hmm bạn có thể thử đổi các câu lệnh case cho ifs mà bạn có .. Tôi chỉ sử dụng case vì chúng là tùy chọn mặc định của tôi (do tính linh hoạt và khả năng đọc của chúng tăng) nhưng có lẽ chúng chậm hơn đáng kể so với trong trường hợp này? cũng phần row_number có thể khá chậm, có thể sẽ có giá trị chỉ làm một lần. – gordatron

1

Tôi khuyên bạn nên sử dụng giao diện API Bugzilla REST thay vì truy cập trực tiếp vào Bugzilla DB. Dưới đây là một API mẫu để truy xuất các lỗi được tạo vào một ngày cụ thể.

https://api-dev.bugzilla.mozilla.org/test/1.3/bug?creation_date=2008-03-31

Tài liệu tham khảo:
https://wiki.mozilla.org/Bugzilla:REST_API
https://wiki.mozilla.org/Bugzilla:REST_API:Objects
https://wiki.mozilla.org/Bugzilla:REST_API:Search

+0

Tôi đã nhìn vào REST API nhưng tôi đọc rằng nó đã khá buggy (mặc dù có thể chỉ là trên phiên bản cũ của chúng tôi, chúng tôi đang cập nhật sớm). Ngoài ra nó có vẻ khá khó khăn để hỏi 'tình trạng của lỗi 1234 vào 2012-01-01' nó vẫn có vẻ như tôi sẽ phải tải xuống và phân tích cú pháp các bộ thay đổi là gì. Tôi đoán có lẽ có một truy vấn boolean phức tạp mà sẽ làm điều đó. Tôi sẽ thử nghiệm khi tôi có cơ hội, nhưng có vẻ như nó sẽ chuyển quá nhiều thông tin qua liên kết chậm để nhanh hơn truy vấn SQL (vì tôi làm COUNT trên số liệu thô và chỉ trả về tổng số thô) . – SpaceDog

+0

Bạn đọc ở đâu rằng API REST khá là lỗi? Là người bảo trì, tôi có thể đảm bảo với bạn rằng các phiên bản hiện tại rất ổn định và được sử dụng cho hàng trăm nghìn truy vấn một tuần bởi dự án Mozilla. Nó sẽ sớm được thay thế bằng một API REST gốc sẽ có giao diện tương tự (với tính năng tương thích) nhưng nhanh hơn nhiều và có ít hạn chế hơn về dữ liệu được trả về. –