2009-01-14 30 views
11

Tôi đang sử dụng một truy vấn SQL tương tự như các hình thức sau đây:ngoài trái tham gia vào hai cột vấn đề hiệu suất

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
AND table1.period = table2.period 

Và đó là một trong hai cách quá chậm hoặc một cái gì đó của deadlocking vì phải mất ít nhất 4 phút để trở về. Nếu tôi thay đổi nó thành:

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
WHERE table1.period = table2.period 

thì nó hoạt động tốt (mặc dù không trả lại đúng số cột). Có cách nào để tăng tốc độ này không?

CẬP NHẬT: Nó làm điều tương tự nếu tôi chuyển sang hai dòng cuối cùng của truy vấn sau:

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.period = table2.period 
WHERE table1.person_uid = table2.person_uid 

UPDATE 2: Đây là những thực sự xem mà tôi đang tham gia. Thật không may, họ đang ở trên một cơ sở dữ liệu tôi không có quyền kiểm soát, vì vậy tôi không thể (dễ dàng) thực hiện bất kỳ thay đổi nào đối với việc lập chỉ mục. Tôi có khuynh hướng đồng ý rằng đây là một vấn đề lập chỉ mục. Tôi sẽ đợi một lúc trước khi chấp nhận câu trả lời trong trường hợp có một số cách kỳ diệu để điều chỉnh truy vấn này mà tôi không biết. Nếu không, tôi sẽ chấp nhận một trong những câu trả lời hiện tại và cố gắng tìm ra một cách khác để làm những gì tôi muốn làm. Cảm ơn sự giúp đỡ của mọi người cho đến nay.

+0

vui lòng cung cấp kế hoạch thực hiện cho truy vấn này – squadette

Trả lời

16

Hãy nhớ rằng các câu 2 và 3 khác với câu lệnh đầu tiên.

Làm cách nào? Vâng, bạn đang làm một phép nối ngoài bên trái và mệnh đề WHERE của bạn không tính đến điều đó (như mệnh đề ON). Ở mức tối thiểu, hãy thử:

SELECT col1, col2 
FROM table1, table2 
WHERE table1.person_uid = table2.person_uid (+) 
AND table1.period = table2.period (+) 

và xem liệu bạn có gặp vấn đề về hiệu suất tương tự hay không.

Bạn có chỉ mục nào trên các bảng này? Mối quan hệ này có được xác định bởi ràng buộc khoá ngoại không?

Những gì bạn có thể cần là chỉ mục tổng hợp trên cả person_uid và dấu chấm (trên cả hai bảng).

+0

Lỗi truy vấn đó mà tôi không thể kết hợp các kết nối bên ngoài ANSI và các kiểu nối ngoài kiểu cũ. –

+0

Đã sửa. Hãy thử điều đó. – cletus

+1

Với các truy vấn ban đầu của bạn với WHERE, cơ sở dữ liệu được tự do lái xe từ bảng 2 tìm nạp các mục nhập table1 trong đó khớp person_uid hoặc dấu chấm câu. Truy vấn ban đầu PHẢI quét toàn bộ bảng 1 và sẽ hoạt động kém nếu có truy cập kém vào bảng 2 (ví dụ: không có chỉ mục hữu ích). –

3

Bạn có chỉ mục bao gồm trên person_uidperiod cho cả hai bảng không?

Nếu không, hãy thêm chúng và thử lại.

Hãy xem kế hoạch thực hiện và xem truy vấn thực sự đang làm gì.

Ngoài ra: Các kiểu dữ liệu của các trường là gì? Họ có giống nhau trong cả hai bảng? Một diễn viên tiềm ẩn thực sự có thể làm chậm mọi thứ.

+0

Um, qestion được gắn thẻ oracle vì vậy tôi không nghĩ rằng anh ấy đang sử dụng SQL Server. – cletus

+0

Ah :) Tôi không thấy ... Không quan trọng ... Kế hoạch thực hiện cũng có sẵn trong oracle ... Tôi sẽ chỉnh sửa câu trả lời. –

2

Những bảng này có chỉ mục trên các cột bạn đang tham gia không? Cài đặt sản phẩm SQLDeveloper miễn phí của Oracle và sử dụng nó để thực hiện một "giải thích" về truy vấn đó và xem nó có thực hiện quét tuần tự của cả hai bảng hay không.

5

Tôi nghĩ bạn cần hiểu lý do tại sao hai câu hỏi cuối cùng không giống như truy vấn đầu tiên. Nếu bạn thực hiện một phép nối trái và sau đó thêm mệnh đề where tham chiếu một trường trong bảng ở bên phải của phép nối (trường có thể không luôn có bản ghi để khớp với bảng đầu tiên), thì bạn đã thay đổi kết nối thành một tham gia bên trong.Có một ngoại lệ cho điều này và đó là nếu bạn tham chiếu một cái gì đó như

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
WHERE table2.person_uid is null 

Trong trường hợp này bạn yêu cầu bản ghi không có bản ghi trong bảng thứ hai. Nhưng ngoài trường hợp đặc biệt này, bạn đang thay đổi phép nối trái thành một phép nối bên trong nếu bạn refence một trường trong bảng 2 trong mệnh đề where.

Nếu truy vấn của bạn không đủ nhanh, tôi sẽ xem xét chỉ mục của bạn.

2

Trong phần nối trái, bạn sẽ quét bảng 1 cho mỗi kết hợp duy nhất của (person_uid, dấu chấm) rồi tìm kiếm bảng2 cho tất cả các bản ghi tương ứng tại đó. Nếu table2 không có chỉ mục thích hợp, điều này có thể liên quan đến việc quét toàn bộ bảng đó.

Dự đoán tốt nhất của tôi, mà không nhìn thấy kế hoạch thực hiện, là truy vấn đầu tiên (truy vấn duy nhất có vẻ chính xác) là phải quét bảng 2 cũng như bảng 1.

Khi bạn nói rằng bạn không thể thay đổi chỉ mục, bạn cần phải thay đổi truy vấn. Theo như tôi có thể nói, chỉ có một thực tế khác ...

SELECT 
    col1, col2 
FROM 
    table2 
FULL OUTER JOIN 
    table1 
     ON table1.person_uid = table2.person_uid 
     AND table1.period = table2.period 
WHERE 
    table1.person_uid IS NOT NULL 

Hy vọng ở đây là bạn quét table2 cho mỗi sự kết hợp độc đáo của (person_uid, thời gian), nhưng sử dụng các chỉ số trên table1. (Trái ngược với quét bảng 1 và sử dụng các chỉ mục trên bảng 2, điều mà tôi mong đợi từ truy vấn của bạn.)

Nếu table1 không có chỉ mục phù hợp, tuy nhiên, bạn sẽ không thấy bất kỳ cải thiện hiệu suất nào tất cả ...

Đêm.

4

Bất cứ điều gì ai nói với bạn dựa trên thông tin bạn đã cung cấp đều là phỏng đoán.

Nhìn vào kế hoạch thực hiện cho truy vấn. Nếu bạn không thấy lý do cho sự chậm chạp trong kế hoạch, hãy đăng kế hoạch ở đây.

http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/ex_plan.htm#PFGRF009

+1

@Dave Costa: Tuyệt đối! Sử dụng dấu vết Oracle để tìm hiểu kế hoạch thực hiện và những gì Oracle đang chờ đợi. Vắng mặt, mọi người chỉ đoán thôi. – spencer7593

+0

http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/sqltrace.htm – spencer7593

0

Trong một trong những cập nhật OP nói rằng ông thực sự là truy vấn quan điểm không bảng. Trong trường hợp này, hiệu năng có thể được tăng lên bằng cách truy vấn trực tiếp các bảng mà anh ta cần đặc biệt nếu các khung nhìn phức tạp và tham gia vào nhiều bảng khác không chứa thông tin anh ta cần hoặc chúng là các khung nhìn gọi các khung nhìn.

0

Cú pháp nối ANSI cung cấp sự phân biệt rất rõ ràng giữa các điều kiện JOIN và các biến vị ngữ FILTER; điều này rất quan trọng khi viết các phép nối ngoài. Sử dụng các bảng emp/dept, nhìn vào kết quả từ hai bên ngoài sau gia nhập

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
LEFT OUTER JOIN emp e 
on d.deptno = e.deptno 
and loc in ('NEW YORK','BOSTON') 
; 

DNAME    DEPTNO ENAME    MGR LOC 
-------------- ---------- ---------- ---------- ------------- 
ACCOUNTING    10 CLARK   7839 NEW YORK 
ACCOUNTING    10 KING     NEW YORK 
ACCOUNTING    10 MILLER   7782 NEW YORK 
RESEARCH    20      DALLAS 
SALES     30      CHICAGO 
OPERATIONS    40      BOSTON 

====

Q2 
SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
LEFT OUTER JOIN emp e 
on d.deptno = e.deptno 
where loc in ('NEW YORK','BOSTON') 
; 

DNAME    DEPTNO ENAME    MGR LOC 
-------------- ---------- ---------- ---------- ------------- 
ACCOUNTING    10 CLARK   7839 NEW YORK 
ACCOUNTING    10 KING     NEW YORK 
ACCOUNTING    10 MILLER   7782 NEW YORK 
OPERATIONS    40      BOSTON 

Ví dụ đầu tiên, Q1 cho thấy là một ví dụ về "tham gia vào một hằng số". Về cơ bản, điều kiện bộ lọc được áp dụng trước khi thực hiện phép nối ngoài. Vì vậy, bạn loại bỏ các hàng, sau đó được thêm trở lại như một phần của kết nối bên ngoài. Nó không nhất thiết phải sai, nhưng đó là truy vấn mà bạn thực sự yêu cầu? Thường thì đó là kết quả được hiển thị trong quý 2 được yêu cầu, trong đó bộ lọc được áp dụng sau khi kết nối (bên ngoài).

Ngoài ra còn có ý nghĩa về hiệu suất, đối với các tập dữ liệu lớn.Trong nhiều trường hợp, việc tham gia vào hằng số phải được trình tối ưu hóa giải quyết nội bộ bằng cách tạo chế độ xem bên, thường chỉ có thể được tối ưu hóa qua tham gia vòng lặp lồng nhau chứ không phải là băm tham gia

Dành cho nhà phát triển quen thuộc với Oracle cú pháp nối ngoài, truy vấn có lẽ sẽ được viết là

SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
     ,emp e 
where d.deptno = e.deptno(+) 
and loc in ('NEW YORK','BOSTON') 

Truy vấn này tương đương về mặt ngữ nghĩa như Q2 ở trên.

Vì vậy, tóm lại, điều cực kỳ quan trọng là bạn hiểu sự khác nhau giữa mệnh đề JOIN và mệnh đề WHERE khi viết các kết nối bên ngoài ANSI.

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