Oracle không sử dụng một chỉ mục duy nhất cho một khóa dài


16

Tôi có một bảng với 250K hàng trong cơ sở dữ liệu thử nghiệm của mình. (Có vài trăm triệu sản xuất, chúng ta có thể quan sát cùng một vấn đề ở đó.) Bảng có mã định danh chuỗi nvarchar2 (50), không phải là null, với chỉ số duy nhất trên đó (không phải là PK).

Các mã định danh được tạo thành từ một phần đầu tiên có 8 giá trị khác nhau trong cơ sở dữ liệu thử nghiệm của tôi (và khoảng một nghìn trong sản xuất), sau đó là dấu @ và cuối cùng là một số, dài từ 1 đến 6 chữ số. Ví dụ: có thể có 50 nghìn hàng bắt đầu bằng 'ABCD_BGX1741F_2006_13_20110808.xml @' và theo sau là 50 nghìn số khác nhau.

Khi tôi truy vấn một hàng duy nhất dựa trên mã định danh của nó, số lượng thẻ được ước tính là 1, chi phí rất thấp, nó hoạt động tốt. Khi tôi truy vấn nhiều hơn một hàng với một số định danh trong biểu thức IN hoặc biểu thức OR, các ước tính cho chỉ mục là hoàn toàn sai, do đó quét toàn bộ bảng được sử dụng. Nếu tôi buộc chỉ mục bằng một gợi ý, thì nó rất nhanh, quá trình quét toàn bộ bảng thực sự được thực hiện theo thứ tự độ lớn chậm hơn (và chậm hơn rất nhiều trong sản xuất). Vì vậy, nó là một vấn đề tối ưu hóa.

Để thử nghiệm, tôi đã nhân đôi bảng (trong cùng một lược đồ + không gian bảng) với cùng một DDL và chính xác cùng một nội dung. Tôi đã tạo lại chỉ mục duy nhất trên bảng đầu tiên để đo lường tốt và tạo ra chỉ mục chính xác tương tự trên bảng nhân bản. Tôi đã làm một DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);. Bạn thậm chí có thể thấy rằng các tên chỉ mục là liên tiếp. Vì vậy, bây giờ sự khác biệt duy nhất giữa hai bảng là bảng đầu tiên được tải theo thứ tự ngẫu nhiên trong một khoảng thời gian dài, với các khối nằm rải rác trên đĩa (trong một không gian bảng cùng với một số bảng lớn khác), bảng thứ hai được tải dưới dạng một nhóm CHỌN-CHỌN. Ngoài ra, tôi không thể tưởng tượng bất kỳ sự khác biệt. (Bảng gốc đã bị thu hẹp kể từ lần xóa lớn cuối cùng và sau đó không có một lần xóa nào.)

Dưới đây là các kế hoạch truy vấn cho người bệnh và bảng nhân bản (Các chuỗi dưới bàn chải màu đen giống nhau trên tất cả các hình ảnh, và cũng dưới bàn chải màu xám.):

kế hoạch truy vấn

(Trong ví dụ này, có 1867 hàng bắt đầu bằng mã định danh được quét màu đen. Truy vấn 2 hàng tạo ra số lượng thẻ là 1867 * 2, truy vấn 3 hàng tạo ra số lượng thẻ là 1867 * 3, v.v. là một sự trùng hợp ngẫu nhiên, Oracle dường như không quan tâm đến sự kết thúc của các định danh.)

Điều gì có thể gây ra hành vi này? Rõ ràng nó sẽ khá tốn kém để tạo lại bảng trong sản xuất.

USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg Tôi chỉ thay đổi tên lược đồ và tên vùng bảng. Bạn có thể thấy rằng tên bảng và chỉ mục giống như trên ảnh chụp màn hình kế hoạch truy vấn.

Câu trả lời:


7

(Điều này trả lời câu hỏi khác về lý do tại sao biểu đồ là khác nhau.)

Biểu đồ được tạo theo mặc định dựa trên độ lệch cột liệu cột có được sử dụng trong một vị từ có liên quan hay không. Sao chép DDL và dữ liệu là không đủ, thông tin khối lượng công việc cũng rất quan trọng.

Theo Hướng dẫn điều chỉnh hiệu suất :

Khi bạn thả bảng, thông tin khối lượng công việc được sử dụng bởi tính năng thu thập biểu đồ tự động và lịch sử thống kê đã lưu được sử dụng bởi các thủ tục RESTORE _ * _ STATS sẽ bị mất. Không có dữ liệu này, các tính năng này không hoạt động đúng.

Ví dụ: đây là bảng có dữ liệu bị lệch nhưng không có biểu đồ:

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
NONE

Chạy cùng một thứ, nhưng với một truy vấn trước khi số liệu thống kê được thu thập, sẽ tạo ra một biểu đồ.

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
select count(*) from test1 where a = sysdate; --Only new line
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
FREQUENCY

2
Ví dụ đơn giản rực rỡ. Bạn có biết tại sao CBO sử dụng biểu đồ cho ước tính cardinality trên một lần quét duy nhất thay vì chỉ giả sử 1 không?
Jack Douglas

Cảm ơn! Tôi đã thực hiện một repro hoàn chỉnh với loại dữ liệu và truy vấn của mình trên blog của mình: joco.name/2014/01/05/ Khăn
fejesjoco

@Jack Tôi nghĩ đó là sự lười biếng. Các kỹ sư của Oracle phải nhận ra rằng các số liệu thống kê của một chỉ mục duy nhất sẽ có cùng số lượng giá trị riêng biệt như các hàng, vì vậy, giả định về số lượng thẻ không phải là khó khăn, mà chỉ được sử dụng từ các số liệu thống kê, như trong mọi trường hợp khác. Ngoài ra, như một trường hợp chung, biểu đồ chiếm ưu thế thống kê đơn giản. Trường hợp của tôi có vẻ rất đặc biệt chỉ vì các phím dài, nhưng tôi tin rằng điều này hoạt động khá tốt nếu không.
fejesjoco

@fejesjoco Tôi nghĩ rằng lời giải thích của JL có nhiều khả năng, vì các biểu đồ cũng sẽ chiếm ưu thế trong các trường hợp tra cứu duy nhất (không có in), phải không? Tôi nghĩ rằng CBO thực hiện giả định cardinality 1, nhưng chỉ trong trường hợp rất đơn giản. Tôi giả sử bạn có thể làm việc xung quanh toàn bộ bằng cách sử dụng lớn UNION ALLnhưng có thể có những lý do khác để không làm điều đó và JL đề cập đến các cách giải quyết khác có thể có trong bài đăng trên blog được liên kết.
Jack Douglas

1
Một bí ẩn nhỏ khác cần xem xét - làm thế nào biểu đồ này được tạo ra ở nơi đầu tiên? Oracle dường như chỉ xem xét một cột bị sai lệch nếu nó có trùng lặp, mà rõ ràng cột duy nhất của bạn không thể có. Có ai đó cố tình xây dựng biểu đồ này (không có khả năng), hoặc ai đó đã thu thập số liệu thống kê với người không được đề xuất method_opt=>'for all indexed columns'?
Jon Heller

8

Tôi tìm thấy giải pháp! Nó thật đẹp và tôi thực sự đã học được rất nhiều về Oracle.

Trong một từ: biểu đồ.

Tôi bắt đầu đọc rất nhiều về cách thức hoạt động của CBO của Oracle và tôi tình cờ thấy được biểu đồ. Tôi không hiểu đầy đủ vì vậy tôi đã xem bảng USER_HISTOGRAM và voilá. Có một số hàng cho bảng bệnh và thực tế không có gì cho bảng nhân bản. Đối với bảng bệnh, có một hàng cho mỗi trong số 8 phần bắt đầu nhận dạng khác nhau. Và đây là chìa khóa: chúng đã bị cắt ở 32 ký tự, trước dấu @. Như tôi đã nói, phần đầu tiên của các khóa có tính lặp lại cao, chúng trở nên khác biệt sau dấu @.

Dường như biểu đồ có thể mạnh hơn thực tế đơn giản là một chỉ số duy nhất luôn có giá trị bằng 0 hoặc 1 cho một giá trị nhất định. Khi tôi truy vấn hơn 2 hàng, Oracle đã nhìn vào biểu đồ, nó nghĩ rằng có thể có hàng chục ngàn giá trị cho phần bắt đầu định danh đó và nó đã ném khóa CBO.

Tôi đã xóa biểu đồ cho cột đó trong bảng cũ và vấn đề đã biến mất!

Đọc thêm: https://bloss.oracle.com/optimizer/entry/how_do_i_drop_an_ex hiện_histogram_on_a_column_and_stop_the_auto_stats_gathering_job_from_creating


2
Tôi đã đề cập rằng trong phòng trò chuyện của chúng tôi :) chat.stackexchange.com/transcript/message/12987649#12987649
Philᵀᴹ

Tôi đã không nhìn thấy điều đó :). Vì vậy, điều kỳ lạ duy nhất là tại sao lại có biểu đồ trong bảng đầu tiên và không phải trong bản sao, tôi nghĩ rằng tập hợp_schema_stats cập nhật mọi thứ, dường như là không.
fejesjoco

6

Tôi đã gửi email cho Jonathan Lewis về điều này và nhận được một câu trả lời rất hữu ích:

Sự kỳ lạ trong tính toán là hệ quả của các giới hạn đối với biểu đồ dựa trên ký tự, xem cụ thể:

http://jonathanlewis.wordpress.com/2010/10/13/frequency-histogram-5/ http://jonathanlewis.wordpress.com/2010/10/19/frequency-histograms-6/

Nhìn vào ví dụ, truy vấn dành cho danh sách IN, không phải cho một hàng đơn, vì vậy dự đoán ban đầu của tôi là trình tối ưu hóa đã sử dụng chiến lược chung để tính toán chọn lọc nhiều hàng thay vì có một đoạn mã trường hợp đặc biệt cho một Danh sách IN trên một khóa chính. Tôi đoán sẽ không quá khó để họ nhận ra trường hợp này, nhưng các nhà phát triển có lẽ đã không cho rằng nó đáng để nỗ lực.

Tôi rất khuyến khích đọc các bài đăng trên blog mà anh ấy liên kết, họ mô tả chi tiết giới hạn của biểu đồ bạn đang chạy đến, ví dụ:

Kết luận : Nếu bạn có chuỗi khá dài và tương tự, các chuỗi trong một cột là ứng cử viên tốt cho biểu đồ tần số (ví dụ: cột trạng thái rất mô tả) thì bạn gặp vấn đề nếu một giá trị rất hiếm trông giống với rất phổ biến giá trị lên tới 32 ký tự đầu tiên. Bạn có thể thấy rằng giải pháp duy nhất là thay đổi danh sách các giá trị pháp lý (mặc dù các chiến lược khác nhau liên quan đến các cột ảo hoặc các chỉ mục dựa trên chức năng có thể bỏ qua vấn đề).


Đáng buồn là biểu đồ có vẻ là một tính năng ít được biết đến, tôi đoán nó bởi vì nó quá sâu đối với một nhà phát triển SQL và hầu hết thời gian họ chỉ làm việc, nhưng thật tốt khi biết có nhiều tài nguyên về nó, tôi chỉ không tìm kiếm đúng vị trí :). Thật tệ khi Oracle cắt giảm 32 byte và đưa ra quyết định tai hại dựa trên điều đó. May mắn thay, tôi không cần bất kỳ điều chỉnh nào, bỏ biểu đồ là một giải pháp hoàn hảo. Các giá trị chính là duy nhất, tôi luôn tìm kiếm 20 giá trị cùng một lúc, nó chỉ hoạt động tốt với một chỉ mục và nó mang tính quyết định. Nhưng tôi sẽ không sử dụng các phím dài vào lần tới, điều đó là chắc chắn.
fejesjoco

Biểu đồ khá nổi tiếng trong số các DBA;) Tôi thích thực tế là bạn có vẻ muốn học những thứ sâu sắc hơn và thực sự nghĩ rằng bạn nên đọc cuốn sách của JL, nó rất rất tốt. CBO thường làm rất tốt: sẽ luôn có những trường hợp cần phải điều tra nhưng điều đáng ghi nhớ là ngay cả khi không bị cắt, các ước tính luôn chỉ là ước tính.
Jack Douglas

1
Nếu bạn chạy một công việc thống kê thông thường (như một Oracle chạy theo mặc định trên một cài đặt sạch), bạn có thể thấy biểu đồ xuất hiện lại, bạn có thể cần xem xét cách ngăn chặn điều đó (chẳng hạn như LOCK_TABLE_STATS có lẽ)
Jack Douglas

Tôi đã đề cập đến một bài đăng blog trong câu trả lời của tôi, có hướng dẫn về cách ngăn chặn biểu đồ cho một cột.
fejesjoco

1
@Jack Douglas, cảm ơn bạn đã liên quan đến J. Lewis và báo cáo lại!
Dimitre Radoulov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.