2010-06-24 25 views
6

Vì vậy, tôi đang truy vấn một số bảng rất lớn. Lý do chúng quá lớn là vì PeopleSoft chèn các bản ghi mới mỗi lần thay đổi được thực hiện cho một số dữ liệu, thay vì cập nhật các bản ghi hiện có. Trong thực tế, các bảng giao dịch của nó cũng là một kho dữ liệu.Làm cách nào để tăng tốc truy vấn đối với bảng kho dữ liệu khổng lồ với dữ liệu có hiệu lực ngày?

Điều này đòi hỏi các truy vấn có lựa chọn lồng nhau trong chúng, để nhận hàng gần đây nhất/hiện tại. Cả hai đều có hiệu lực ngày và trong mỗi ngày (đúc một ngày) họ có thể có một trình tự hiệu quả. Do đó, để có được kỷ lục hiện tại cho user_id=123, tôi phải làm điều này:

select * from sometable st 
where st.user_id = 123 
and st.effective_date = (select max(sti.effective_date) 
    from sometable sti where sti.user_id = st.user_id) 
and st.effective_sequence = (select max(sti.effective_sequence) 
    from sometable sti where sti.user_id = st.user_id 
    and sti.effective_date = st.effective_date) 

Có một số hiện tượng các chỉ số trên các bảng, và tôi không thể tìm thấy bất cứ điều gì khác mà có thể tăng tốc độ truy vấn của tôi .

Rắc rối của tôi là tôi thường muốn nhận dữ liệu về một cá nhân từ các bảng này có thể 50 user_ids, nhưng khi tôi tham gia các bảng của tôi chỉ có một vài bản ghi trong đó với một vài bảng PeopleSoft này để crap.

Bảng PeopleSoft nằm trên cơ sở dữ liệu từ xa mà tôi truy cập thông qua liên kết cơ sở dữ liệu. Truy vấn của tôi có xu hướng trông giống như sau:

select st.* from local_table lt, [email protected] st 
where lt.user_id in ('123', '456', '789') 
and lt.user_id = st.user_id 
and st.effective_date = (select max(sti.effective_date) 
    from [email protected] sti where sti.user_id = st.user_id) 
and st.effective_sequence = (select max(sti.effective_sequence) 
    from [email protected] sti where sti.user_id = st.user_id 
    and sti.effective_date = st.effective_date) 

Mọi thứ trở nên tồi tệ hơn khi tôi phải tham gia một số bảng PeopleSoft với bảng cục bộ của mình. Hiệu suất chỉ là không thể chấp nhận được.

Tôi có thể làm gì để cải thiện hiệu suất? Tôi đã thử các gợi ý truy vấn để đảm bảo rằng bảng cục bộ của tôi được nối với đối tác của nó trong PeopleSoft trước, vì vậy nó không cố gắng nối tất cả các bảng của nó với nhau trước khi thu hẹp nó xuống đúng user_id. Tôi đã thử các gợi ý LEADING và toyed xung quanh với gợi ý đã cố gắng để đẩy chế biến đến cơ sở dữ liệu từ xa, nhưng kế hoạch giải thích đã được che khuất và chỉ nói 'REMOTE' cho một số hoạt động và tôi không có ý tưởng những gì đang xảy ra.

Giả sử tôi không có khả năng thay đổi PeopleSoft và vị trí của các bảng của tôi, là gợi ý lựa chọn tốt nhất của tôi? Nếu tôi đang tham gia một bảng cục bộ với bốn bảng từ xa và bảng cục bộ được kết hợp với hai bảng, tôi sẽ định dạng gợi ý sao cho bảng cục bộ của tôi (rất nhỏ - thực tế, tôi chỉ có thể thực hiện chế độ xem nội tuyến để có bảng địa phương của tôi chỉ là user_ids tôi quan tâm) được tham gia đầu tiên với từng cái từ xa?

CHỈNH SỬA: Ứng dụng cần dữ liệu thời gian thực, vì vậy rất tiếc một chế độ xem được thực hiện hoặc phương pháp lưu dữ liệu bộ nhớ đệm khác sẽ không đủ.

+2

+1, bất kỳ ai đã phải đối mặt với việc tham gia liên kết DB đều có thể đánh giá cao điều này. – DCookie

+0

Bạn có thể đăng kế hoạch giải thích cho các truy vấn này không? – APC

+1

Bạn có thể sử dụng chế độ xem hiện thực hóa nếu DB của bạn hỗ trợ cập nhật háo hức. –

Trả lời

4

Tái cấu trúc lại truy vấn của bạn giống như trợ giúp này?

SELECT * 
    FROM (SELECT st.*, MAX(st.effective_date) OVER (PARTITION BY st.user_id) max_dt, 
        MAX(st.effective_sequence) OVER (PARTITION BY st.user_id, st.effective_date) max_seq 
      FROM local_table lt JOIN [email protected] st ON (lt.user_id = st.user_id) 
     WHERE lt.user_id in ('123', '456', '789')) 
WHERE effective_date = max_dt 
    AND effective_seq = max_seq; 

Tôi đồng ý với @Mark Baker rằng hiệu suất tham gia liên kết DB thực sự có thể hút và bạn có thể bị giới hạn ở những gì bạn có thể thực hiện với phương pháp này.

+0

Tôi không biết làm thế nào điều này hoạt động nội bộ nhưng nó mang lại cho tôi một hiệu suất đáng kể đạt được trên truy vấn ban đầu của tôi. –

+0

Tôi không biết chắc chắn nhưng cảm giác ruột của tôi là mỗi một truy vấn con của bạn trong mệnh đề where của bạn đã gây ra một truy vấn riêng biệt trên DB từ xa, trong khi truy vấn này nhận mọi thứ chỉ với một lần truy cập. – DCookie

0

Thay vì sử dụng các truy vấn phụ, bạn có thể thử điều này. Tôi không biết liệu Oracle có thực hiện tốt hơn với điều này hay không, vì tôi không sử dụng Oracle nhiều.

SELECT 
    ST1.col1, 
    ST1.col2, 
    ... 
FROM 
    Some_Table ST1 
LEFT OUTER JOIN Some_Table ST2 ON 
    ST2.user_id = ST1.user_id AND 
    (
     ST2.effective_date > ST1.effective_date OR 
     (
      ST2.effective_date = ST1.effective_date AND 
      ST2.effective_sequence > ST1.effective_sequence 
     ) 
    ) 
WHERE 
    ST2.user_id IS NULL 

Một giải pháp khả thi sẽ là:

SELECT 
    ST1.col1, 
    ST1.col2, 
    ... 
FROM 
    Some_Table ST1 
WHERE 
    NOT EXISTS 
    (
     SELECT 
     FROM 
      Some_Table ST2 
     WHERE 
      ST2.user_id = ST1.user_id AND 
      (
       ST2.effective_date > ST1.effective_date OR 
       (
        ST2.effective_date = ST1.effective_date AND 
        ST2.effective_sequence > ST1.effective_sequence 
       ) 
      ) 
    ) 
0

Nó sẽ là một lựa chọn để tạo ra một cơ sở dữ liệu mà bạn sử dụng cho phi kho loại công cụ mà bạn có thể cập nhật trên cơ sở hàng đêm? Nếu đó là bạn có thể tạo ra một quy trình hàng đêm sẽ chỉ di chuyển qua các hồ sơ gần đây nhất. Điều đó sẽ loại bỏ những thứ MAX bạn đang làm cho các truy vấn hàng ngày và giảm đáng kể số lượng hoặc bản ghi.

Ngoài ra, tùy thuộc vào việc bạn có thể có khoảng thời gian 1 ngày giữa dữ liệu gần đây nhất và những gì có sẵn hay không.

Tôi không siêu quen thuộc với Oracle do đó có thể là một cách để có được sự cải thiện bằng cách thay đổi truy vấn của bạn cũng ...

1

Bạn đã không đề cập đến các yêu cầu về độ tươi của dữ liệu, nhưng một tùy chọn sẽ là tạo các khung nhìn vật hoá (bạn sẽ bị giới hạn trong REFRESH COMPLETE vì bạn không thể tạo các bản ghi ảnh chụp nhanh trong hệ thống nguồn) chỉ có dữ liệu cho hàng phiên bản hiện tại của các bảng giao dịch. Các bảng xem vật chất này sẽ nằm trong hệ thống cục bộ của bạn và có thể thêm chỉ mục bổ sung vào chúng để cải thiện hiệu suất truy vấn.

+0

Tôi thích ý tưởng, nhưng dữ liệu cần phải là thời gian thực. –

+0

sau đó xem xét một khung nhìn vật hoá trong DB từ xa liệt kê hàng gần đây nhất cho mỗi userid. Điều này sẽ làm giảm khối lượng dữ liệu di chuyển qua liên kết từ xa. – Karl

1

Sự cố hiệu suất sẽ là quyền truy cập trên toàn liên kết. Với một phần của truy vấn đối với các bảng cục bộ, tất cả đều được thực thi cục bộ để không truy cập vào các chỉ mục từ xa và nó kéo tất cả dữ liệu từ xa trở lại để kiểm tra lkocally.

Nếu bạn có thể sử dụng khung nhìn vật chất trong cơ sở dữ liệu cục bộ được làm mới từ cơ sở dữ liệu của người dùng trên cơ sở dữ liệu lịch sử, chỉ truy cập cơ sở dữ liệu từ xa của người dùng thay đổi ngày nay (thêm mệnh đề effective_date = today to where) và hợp nhất hai truy vấn.

Một tùy chọn khác có thể là sử dụng INSERT INTO X SELECT FROM cho dữ liệu từ xa để kéo nó vào bảng cục bộ tạm thời hoặc chế độ xem vật hoá, sau đó truy vấn thứ hai để kết hợp với dữ liệu cục bộ của bạn ... tương tự như josephj1989's gợi ý

Cách khác (mặc dù có thể có vấn đề về cấp phép) hãy thử RAC Phân cụm db cục bộ của bạn với db từ xa của mọi người.

3

Tùy chọn đầu tiên là thực hiện phần từ xa của truy vấn bằng cách sử dụng biểu thức bảng chung để bạn có thể chắc chắn chỉ dữ liệu có liên quan được tìm nạp từ db từ xa. subquery dựa trên chức năng phân tích. Một truy vấn có thể được sử dụng trong truy vấn hiện tại của bạn. Tôi có thể đưa ra các gợi ý khác chỉ sau khi chơi với db.

xem dưới đây

with remote_query as 
(
    select /*+ materialize */ st.* from [email protected] st 
    where st.user_id in ('123', '456', '789') 
    and st.rowid in(select first_value(rowid) over (order by effective_date desc, 
         effective_sequence desc) from [email protected] st1 
         where st.user_id=st1.user_id) 
) 

select lt.*,st.* 
FROM local_table st,remote_query rt 
where st.user_id=rt.user_id 
+1

+1, như cách bạn sử dụng phân tích. Tôi nghĩ rằng bạn có thể gian lận một chút trong giả định một danh sách cứng của user_id có thể được xác định trong mệnh đề WITH của bạn, mặc dù - nếu nó đơn giản, bạn sẽ không cần tham gia vào local_table ở nơi đầu tiên. – DCookie

0

Bạn có thể ETL các hàng với của user_id mong muốn vào bảng của riêng bạn, tạo ra chỉ các chỉ số cần thiết để hỗ trợ các truy vấn của bạn và thực hiện truy vấn của bạn trên đó?

0

Bảng PeopleSoft có được phân phối hay tùy chỉnh không? Bạn có chắc chắn đó là một bảng vật lý, và không phải là một cái nhìn kém bằng văn bản về phía PS? Nếu đó là bản ghi được phân phối mà bạn sẽ chống lại (ví dụ giống như PS_JOB hoặc chế độ xem tham chiếu đến nó), có thể bạn có thể chỉ ra điều này. PS_JOB là một con thú với hàng tấn chỉ mục được phân phối và hầu hết các trang web đều thêm nhiều hơn nữa.

Nếu bạn biết các chỉ mục trên bảng, bạn có thể sử dụng các gợi ý của Oracle để chỉ định chỉ mục ưa thích để sử dụng; đôi khi có ích.

Bạn đã thực hiện một kế hoạch giải thích để xem liệu bạn có thể xác định được vấn đề ở đâu không? Có lẽ có một tham gia Descartes, quét bảng đầy đủ, vv?

4

Một cách tiếp cận sẽ là gắn các hàm PL/SQL xung quanh mọi thứ. Như một ví dụ

create table remote (user_id number, eff_date date, eff_seq number, value varchar2(10)); 

create type typ_remote as object (user_id number, eff_date date, eff_seq number, value varchar2(10)); 
. 
/

create type typ_tab_remote as table of typ_remote; 
. 
/

insert into remote values (1, date '2010-01-02', 1, 'a'); 
insert into remote values (1, date '2010-01-02', 2, 'b'); 
insert into remote values (1, date '2010-01-02', 3, 'c'); 
insert into remote values (1, date '2010-01-03', 1, 'd'); 
insert into remote values (1, date '2010-01-03', 2, 'e'); 
insert into remote values (1, date '2010-01-03', 3, 'f'); 

insert into remote values (2, date '2010-01-02', 1, 'a'); 
insert into remote values (2, date '2010-01-02', 2, 'b'); 
insert into remote values (2, date '2010-01-03', 1, 'd'); 

create function show_remote (i_user_id_1 in number, i_user_id_2 in number) return typ_tab_remote pipelined is 
    CURSOR c_1 is 
    SELECT user_id, eff_date, eff_seq, value 
    FROM 
     (select user_id, eff_date, eff_seq, value, 
         rank() over (partition by user_id order by eff_date desc, eff_seq desc) rnk 
     from remote 
     where user_id in (i_user_id_1,i_user_id_2)) 
    WHERE rnk = 1; 
begin 
    for c_rec in c_1 loop 
     pipe row (typ_remote(c_rec.user_id, c_rec.eff_date, c_rec.eff_seq, c_rec.value)); 
    end loop; 
    return; 
end; 
/

select * from table(show_remote(1,null)); 

select * from table(show_remote(1,2)); 

Thay vì phải của user_id qua gọi riêng là thông số, bạn có thể tải chúng vào một bảng địa phương (ví dụ như một bảng tạm thời toàn cầu). PL/SQL sẽ lặp lại sau đó thông qua bảng, làm điều khiển từ xa được chọn cho mỗi hàng trong bảng cục bộ. Không có truy vấn đơn lẻ nào có cả bảng cục bộ và từ xa. Có hiệu quả bạn sẽ viết mã tham gia của riêng bạn.

+0

+1 Tôi thích suy nghĩ của bạn –

+0

+1, bây giờ, cho một cái gì đó hoàn toàn khác ... – DCookie

0

Dường như với tôi rằng bạn đang xử lý thứ nguyên loại 2 trong kho dữ liệu. Có một số cách để triển khai kích thước loại 2, chủ yếu là có các cột như ValidFrom, ValidTo, Version, Status. Không phải tất cả chúng đều có mặt, sẽ rất thú vị nếu bạn có thể đăng lược đồ cho bảng của bạn. Dưới đây là một ví dụ về cách nó có thể trông giống như (John Smith chuyển từ Indiana để Ohio vào 2010-06-24)

UserKey UserBusinessKey State ValidFrom ValidTo Version Status 
7234  John_Smith_17 Indiana 2005-03-20 2010-06-23 1  expired 
9116  John_Smith_17 Ohio  2010-06-24 3000-01-01 2  current 

Để có được phiên bản mới nhất của một hàng, người ta thường sử dụng

WHERE Status = 'current' 

hoặc

WHERE ValidTo = '3000-01-01' 

Lưu ý rằng chương trình này có một số liên tục xa trong tương lai.

hoặc

WHERE ValidTo > CURRENT_DATE 

Có vẻ rằng ví dụ của bạn sử dụng ValidFrom (EFFECTIVE_DATE), vì vậy bạn buộc phải tìm max() để xác định vị trí hàng mới nhất. Hãy xem sơ đồ - có Status or ValidTo tương đương trong bảng của bạn không?

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