Chỉ số tổng hợp: Cột chọn lọc đầu tiên?


17

Tôi đã đọc về composite indexesvà tôi hơi bối rối về việc đặt hàng. Tài liệu này (ít hơn một nửa xuống) nói

Nói chung, bạn nên đặt cột dự kiến ​​sẽ được sử dụng thường xuyên nhất đầu tiên trong chỉ mục.

Tuy nhiên, ngay sau khi nó nói

tạo một chỉ mục tổng hợp đặt cột chọn lọc nhất trước tiên; đó là cột có nhiều giá trị nhất

Nói cách khác, Oracle cũng nói nó ở đây

Nếu tất cả các khóa được sử dụng trong mệnh đề WHERE thường xuyên như nhau, thì việc sắp xếp các khóa này từ chọn lọc nhất đến chọn lọc ít nhất trong câu lệnh CREATE INDEX sẽ cải thiện tốt nhất hiệu năng truy vấn.

Tuy nhiên, tôi đã tìm thấy một câu trả lời SO nói khác đi. Nó nói rằng

Sắp xếp các cột với cột ít chọn nhất trước và cột chọn nhiều nhất cuối cùng. Trong trường hợp của một dây buộc với cột có nhiều khả năng sẽ được sử dụng riêng.

Tài liệu đầu tiên tôi tham chiếu nói rằng trước tiên bạn nên sử dụng thường xuyên nhất trong khi câu trả lời SO nói rằng chỉ nên dùng để phá vỡ cà vạt. Sau đó, họ cũng khác nhau về thứ tự.

Tài liệu này cũng nói về skip scanningvà nói

Bỏ qua quét là thuận lợi nếu có một vài giá trị riêng biệt trong cột hàng đầu của chỉ mục tổng hợp và nhiều giá trị riêng biệt trong khóa không ghi của chỉ mục.

Một bài báo khác nói

Cột tiền tố phải là phân biệt đối xử nhất và được sử dụng rộng rãi nhất trong các truy vấn

mà tôi tin rằng hầu hết phân biệt đối xử sẽ có nghĩa là đặc biệt nhất.

Tất cả các nghiên cứu này vẫn dẫn tôi đến cùng một câu hỏi; Cột được chọn nhiều nhất là đầu tiên hay cuối cùng? Cột đầu tiên có nên được sử dụng nhiều nhất và chỉ được chọn nhiều nhất khi kết thúc?

Những bài viết này dường như mâu thuẫn với nhau, nhưng chúng đưa ra một số ví dụ. Từ những gì tôi đã thu thập được, có vẻ hiệu quả hơn cho việc least selective columnlà người đầu tiên trong đơn đặt hàng nếu bạn dự đoán Index Skip Scans. Nhưng tôi không thực sự chắc chắn nếu điều đó là chính xác.


Câu trả lời:


8

Từ AskTom

(trong 9i, có một "quét bỏ qua chỉ mục" mới - tìm kiếm ở đó để đọc về điều đó. Nó làm cho chỉ mục (a, b) HOẶC (b, a) đôi khi hữu ích trong cả hai trường hợp trên!)

Vì vậy, thứ tự các cột trong chỉ mục của bạn phụ thuộc vào CÁCH SỐ LƯỢNG CỦA BẠN được viết. Bạn muốn có thể sử dụng chỉ mục cho càng nhiều truy vấn càng tốt (để cắt giảm hơn tất cả số lượng chỉ mục bạn có) - điều đó sẽ điều khiển thứ tự của các cột. Không có gì khác (tính chọn lọc của a hoặc b hoàn toàn không được tính).

Một trong những đối số để sắp xếp các cột trong chỉ mục tổng hợp theo thứ tự từ ít phân biệt nhất (giá trị ít khác biệt) đến phân biệt đối xử nhất (giá trị khác biệt hơn) là để nén khóa chỉ mục.

SQL> create table t as select * from all_objects;

Table created.

SQL> create index t_idx_1 on t(owner,object_type,object_name);

Index created.

SQL> create index t_idx_2 on t(object_name,object_type,owner);

Index created.

SQL> select count(distinct owner), count(distinct object_type), count(distinct object_name ), count(*)  from t;

COUNT(DISTINCTOWNER) COUNT(DISTINCTOBJECT_TYPE) COUNT(DISTINCTOBJECT_NAME)      COUNT(*)
-------------------- -------------------------- --------------------------      ----------
                 30                         45                       52205      89807

SQL> analyze index t_idx_1 validate structure; 

Index analyzed.

SQL> select btree_space, pct_used, opt_cmpr_count, opt_cmpr_pctsave from index_stats;

BTREE_SPACE   PCT_USED OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
----------- ---------- -------------- ----------------
    5085584     90          2           28

SQL> analyze index t_idx_2 validate structure; 

Index analyzed.

SQL> select btree_space, pct_used, opt_cmpr_count, opt_cmpr_pctsave  from index_stats; 

BTREE_SPACE   PCT_USED OPT_CMPR_COUNT OPT_CMPR_PCTSAVE
----------- ---------- -------------- ----------------
    5085584     90          1           14

Theo thống kê chỉ số, chỉ số đầu tiên dễ nén hơn.

Một cách khác là cách chỉ mục được sử dụng trong các truy vấn của bạn. Nếu truy vấn của bạn chủ yếu sử dụng col1,

Ví dụ: nếu bạn có các truy vấn như-

  • select * from t where col1 = :a and col2 = :b;
  • select * from t where col1 = :a;

    -then index(col1,col2)sẽ thực hiện tốt hơn.

    Nếu truy vấn của bạn chủ yếu sử dụng col2,

  • select * from t where col1 = :a and col2 = :b;
  • select * from t where col2 = :b;

    -then index(col2,col1)sẽ thực hiện tốt hơn. Nếu tất cả các truy vấn của bạn luôn chỉ định cả hai cột thì việc cột nào đứng đầu trong chỉ mục tổng hợp không thành vấn đề.

    Tóm lại, các cân nhắc chính trong thứ tự cột của chỉ mục tổng hợp là nén khóa chỉ mục và cách bạn sẽ sử dụng chỉ mục này trong các truy vấn của mình.

    Người giới thiệu:

  • Thứ tự cột trong Index
  • Sẽ kém hiệu quả hơn khi có các cột hàng đầu thấp trong một chỉ số (Phải)?
  • Index Skip Scan - Liệu cột Index có vấn đề gì nữa không? (Dấu hiệu cảnh báo)


  • 3

    Phần lớn chọn lọc đầu tiên chỉ hữu ích khi cột này nằm trong mệnh đề WHERE thực tế.

    Khi CHỌN là bởi một nhóm lớn hơn (ít chọn lọc hơn) và sau đó có thể bởi các giá trị khác, không được lập chỉ mục, một chỉ mục có các cột ít chọn lọc hơn vẫn có thể hữu ích (nếu có lý do không tạo một giá trị khác).

    Nếu có bảng ĐỊA CHỈ, với

    ĐƯỜNG QUỐC GIA, một cái gì đó khác ...

    lập chỉ mục ĐƯỜNG, THÀNH PHỐ, QUỐC GIA sẽ mang lại các truy vấn nhanh nhất với tên đường phố. Nhưng truy vấn tất cả các đường phố của một thành phố, chỉ mục sẽ vô dụng và truy vấn có thể sẽ thực hiện quét toàn bộ bảng.

    Lập chỉ mục QUỐC GIA, THÀNH PHỐ, ĐƯỜNG có thể chậm hơn một chút cho từng đường phố, nhưng chỉ mục có thể được sử dụng cho các truy vấn khác, chỉ chọn theo quốc gia và / hoặc thành phố.


    3

    Khi chọn thứ tự cột chỉ mục, mối quan tâm ghi đè là:

    Có các vị từ (bình đẳng) đối với cột này trong các truy vấn của tôi không?

    Nếu một cột không bao giờ xuất hiện trong mệnh đề where, thì nó không có giá trị lập chỉ mục (1)

    OK, vậy là bạn đã có một bảng và truy vấn đối với từng cột. Đôi khi nhiều hơn một.

    Làm thế nào để bạn quyết định những gì để lập chỉ mục?

    Hãy xem một ví dụ. Đây là một bảng có ba cột. Một giữ 10 giá trị, 1.000 khác, 10.000 cuối cùng:

    create table t(
      few_vals  varchar2(10),
      many_vals varchar2(10),
      lots_vals varchar2(10)
    );
    
    insert into t 
    with rws as (
      select lpad(mod(rownum, 10), 10, '0'), 
             lpad(mod(rownum, 1000), 10, '0'), 
             lpad(rownum, 10, '0') 
      from dual connect by level <= 10000
    )
      select * from rws;
    
    commit;
    
    select count(distinct few_vals),
           count(distinct many_vals) ,
           count(distinct lots_vals) 
    from   t;
    
    COUNT(DISTINCTFEW_VALS)  COUNT(DISTINCTMANY_VALS)  COUNT(DISTINCTLOTS_VALS)  
    10                       1,000                     10,000     
    

    Đây là những con số được đệm bằng số không. Điều này sẽ giúp làm cho điểm về nén sau này.

    Vì vậy, bạn đã có ba truy vấn phổ biến:

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001';
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001';
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001'
    and    few_vals = '0000000001';
    

    Bạn lập chỉ mục gì?

    Một chỉ mục trên vài số chỉ tốt hơn một chút so với quét toàn bộ bảng:

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001';
    
    select * 
    from table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------  
    | Id  | Operation            | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT     |          |      1 |        |      1 |00:00:00.01 |      61 |  
    |   1 |  SORT AGGREGATE      |          |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   2 |   VIEW               | VW_DAG_0 |      1 |   1000 |   1000 |00:00:00.01 |      61 |  
    |   3 |    HASH GROUP BY     |          |      1 |   1000 |   1000 |00:00:00.01 |      61 |  
    |   4 |     TABLE ACCESS FULL| T        |      1 |   1000 |   1000 |00:00:00.01 |      61 |  
    -------------------------------------------------------------------------------------------
    
    select /*+ index (t (few_vals)) */
           count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      58 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      58 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |   1000 |   1000 |00:00:00.01 |      58 |  
    |   3 |    HASH GROUP BY                       |          |      1 |   1000 |   1000 |00:00:00.01 |      58 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |   1000 |   1000 |00:00:00.01 |      58 |  
    |   5 |      INDEX RANGE SCAN                  | FEW      |      1 |   1000 |   1000 |00:00:00.01 |       5 |  
    -------------------------------------------------------------------------------------------------------------
    

    Vì vậy, nó không có khả năng tự lập chỉ mục. Các truy vấn trên rất nhiều trả về vài hàng (chỉ 1 trong trường hợp này). Vì vậy, đây chắc chắn là chỉ số giá trị.

    Nhưng những gì về các truy vấn đối với cả hai cột?

    Bạn nên lập chỉ mục:

    ( few_vals, lots_vals )

    HOẶC LÀ

    ( lots_vals, few_vals )

    Câu hỏi mẹo!

    Câu trả lời là không.

    Chắc chắn vài_ số là một chuỗi dài. Vì vậy, bạn có thể có được nén tốt từ nó. Và bạn (có thể) có được một lần quét bỏ qua chỉ mục cho các truy vấn bằng cách sử dụng (few_ số, lot_ số) chỉ có các vị từ trên rất nhiều. Nhưng tôi không ở đây, mặc dù nó hoạt động tốt hơn rõ rệt so với quét toàn bộ:

    create index few_lots on t(few_vals, lots_vals);
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------  
    | Id  | Operation            | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT     |          |      1 |        |      1 |00:00:00.01 |      61 |  
    |   1 |  SORT AGGREGATE      |          |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   2 |   VIEW               | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   3 |    HASH GROUP BY     |          |      1 |      1 |      1 |00:00:00.01 |      61 |  
    |   4 |     TABLE ACCESS FULL| T        |      1 |      1 |      1 |00:00:00.01 |      61 |  
    -------------------------------------------------------------------------------------------  
    
    select /*+ index_ss (t few_lots) */count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    ----------------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  
    ----------------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      13 |     11 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |      1 |00:00:00.01 |      13 |     11 |  
    |   5 |      INDEX SKIP SCAN                   | FEW_LOTS |      1 |     40 |      1 |00:00:00.01 |      12 |     11 |  
    ----------------------------------------------------------------------------------------------------------------------
    

    Bạn có thích cờ bạc không? (2)

    Vì vậy, bạn vẫn cần một chỉ mục với rất nhiều cột làm cột hàng đầu. Và ít nhất trong trường hợp này, chỉ số ghép (vài, rất nhiều) thực hiện cùng một lượng công việc như một chỉ trên (rất nhiều)

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001'
    and    few_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |       3 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |      1 |00:00:00.01 |       3 |  
    |   5 |      INDEX RANGE SCAN                  | FEW_LOTS |      1 |      1 |      1 |00:00:00.01 |       2 |  
    -------------------------------------------------------------------------------------------------------------  
    
    create index lots on t(lots_vals);
    
    select /*+ index (t (lots_vals)) */count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  lots_vals = '0000000001'
    and    few_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    ----------------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  
    ----------------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |       3 |      1 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      1 |      1 |00:00:00.01 |       3 |      1 |  
    |   5 |      INDEX RANGE SCAN                  | LOTS     |      1 |      1 |      1 |00:00:00.01 |       2 |      1 |  
    ----------------------------------------------------------------------------------------------------------------------  
    

    Sẽ có trường hợp chỉ số ghép giúp bạn tiết kiệm 1-2 IOs. Nhưng nó có đáng để có hai chỉ số cho việc tiết kiệm này không?

    Và có một vấn đề khác với chỉ số tổng hợp. So sánh hệ số phân cụm cho ba chỉ mục bao gồm LOTS_VALS:

    create index lots on t(lots_vals);
    create index lots_few on t(lots_vals, few_vals);
    create index few_lots on t(few_vals, lots_vals);
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor
    from   user_indexes
    where  table_name = 'T';
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    FEW_LOTS    47           10,000         530                
    LOTS_FEW    47           10,000         53                 
    LOTS        31           10,000         53                 
    FEW         31           10             530    
    

    Lưu ý rằng hệ số phân cụm cho few_lots cao hơn gấp 10 lần so với lot và lot_few! Và đây là trong một bảng demo với phân cụm hoàn hảo để bắt đầu. Trong cơ sở dữ liệu thế giới thực, hiệu quả có thể tồi tệ hơn.

    Vì vậy, những gì xấu về điều đó?

    Yếu tố phân cụm là một trong những yếu tố chính quyết định mức độ "hấp dẫn" của một chỉ mục. Nó càng cao, càng ít khả năng tối ưu hóa để chọn nó. Đặc biệt nếu lot_ số không thực sự là duy nhất, nhưng thông thường vẫn có vài hàng cho mỗi giá trị. Nếu bạn không may mắn, điều này có thể đủ để làm cho trình tối ưu hóa nghĩ rằng quét toàn bộ sẽ rẻ hơn ...

    OK, do đó, các chỉ mục tổng hợp có vài số và rất nhiều chỉ có lợi ích trường hợp cạnh.

    Điều gì về các truy vấn lọc vài số và nhiều số?

    Chỉ mục cột đơn chỉ cung cấp lợi ích nhỏ. Nhưng kết hợp họ trả lại một vài giá trị. Vì vậy, một chỉ số tổng hợp là một ý tưởng tốt. Nhưng đường nào vòng?

    Nếu bạn đặt vài cái trước, nén cột hàng đầu sẽ làm cho nó nhỏ hơn

    create index few_many on t(many_vals, few_vals);
    create index many_few on t(few_vals, many_vals);
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor 
    from   user_indexes
    where  index_name in ('FEW_MANY', 'MANY_FEW');
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    FEW_MANY    47           1,000          10,000             
    MANY_FEW    47           1,000          10,000   
    
    alter index few_many rebuild compress 1;
    alter index many_few rebuild compress 1;
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor 
    from   user_indexes
    where  index_name in ('FEW_MANY', 'MANY_FEW');
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    MANY_FEW    31           1,000          10,000             
    FEW_MANY    34           1,000          10,000      
    

    Với ít giá trị khác nhau trong cột hàng đầu sẽ nén tốt hơn. Vì vậy, có rất ít công việc để đọc chỉ số này. Nhưng chỉ một chút thôi. Và cả hai đã là một đoạn tốt nhỏ hơn so với ban đầu (giảm 25% kích thước).

    Và bạn có thể đi xa hơn và nén toàn bộ chỉ số!

    alter index few_many rebuild compress 2;
    alter index many_few rebuild compress 2;
    
    select index_name, leaf_blocks, distinct_keys, clustering_factor 
    from   user_indexes
    where  index_name in ('FEW_MANY', 'MANY_FEW');
    
    INDEX_NAME  LEAF_BLOCKS  DISTINCT_KEYS  CLUSTERING_FACTOR  
    FEW_MANY    20           1,000          10,000             
    MANY_FEW    20           1,000          10,000   
    

    Bây giờ cả hai chỉ mục trở lại cùng kích thước. Lưu ý điều này lợi dụng thực tế là có một mối quan hệ giữa vài và nhiều. Một lần nữa, không chắc bạn sẽ thấy loại lợi ích này trong thế giới thực.

    Cho đến nay chúng ta chỉ nói về kiểm tra bình đẳng. Thông thường với các chỉ mục tổng hợp, bạn sẽ có bất đẳng thức so với một trong các cột. ví dụ: các truy vấn như "nhận đơn đặt hàng / giao hàng / hóa đơn cho khách hàng trong N ngày qua".

    Nếu bạn có các loại truy vấn này, bạn muốn có sự bằng nhau so với cột đầu tiên của chỉ mục:

    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals < '0000000002'
    and    many_vals = '0000000001';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    -------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  
    -------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      12 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      12 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |     10 |     10 |00:00:00.01 |      12 |  
    |   3 |    HASH GROUP BY                       |          |      1 |     10 |     10 |00:00:00.01 |      12 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |     10 |     10 |00:00:00.01 |      12 |  
    |   5 |      INDEX RANGE SCAN                  | FEW_MANY |      1 |     10 |     10 |00:00:00.01 |       2 |  
    -------------------------------------------------------------------------------------------------------------  
    
    select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )
    from   t
    where  few_vals = '0000000001'
    and    many_vals < '0000000002';
    
    select * 
    from   table(dbms_xplan.display_cursor(null, null, 'IOSTATS LAST -PREDICATE'));
    
    ----------------------------------------------------------------------------------------------------------------------  
    | Id  | Operation                              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  
    ----------------------------------------------------------------------------------------------------------------------  
    |   0 | SELECT STATEMENT                       |          |      1 |        |      1 |00:00:00.01 |      12 |      1 |  
    |   1 |  SORT AGGREGATE                        |          |      1 |      1 |      1 |00:00:00.01 |      12 |      1 |  
    |   2 |   VIEW                                 | VW_DAG_0 |      1 |      2 |     10 |00:00:00.01 |      12 |      1 |  
    |   3 |    HASH GROUP BY                       |          |      1 |      2 |     10 |00:00:00.01 |      12 |      1 |  
    |   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| T        |      1 |      2 |     10 |00:00:00.01 |      12 |      1 |  
    |   5 |      INDEX RANGE SCAN                  | MANY_FEW |      1 |      1 |     10 |00:00:00.01 |       2 |      1 |  
    ----------------------------------------------------------------------------------------------------------------------  
    

    Lưu ý rằng họ đang sử dụng chỉ mục ngược lại.

    TL; DR

    • Các cột có điều kiện bình đẳng nên đi đầu tiên trong chỉ mục.
    • Nếu bạn có nhiều cột có giá trị bằng nhau trong truy vấn của mình, đặt cột có ít giá trị khác nhau trước sẽ mang lại lợi thế nén tốt nhất
    • Mặc dù quét bỏ qua chỉ mục là có thể, bạn cần phải tự tin rằng đây sẽ vẫn là một lựa chọn khả thi cho tương lai gần
    • Các chỉ mục tổng hợp bao gồm các cột gần như duy nhất mang lại lợi ích tối thiểu. Hãy chắc chắn rằng bạn thực sự cần phải lưu 1-2 IO

    1: Trong một số trường hợp, có thể có giá trị bao gồm một cột trong một chỉ mục nếu điều này có nghĩa là tất cả các cột trong truy vấn của bạn nằm trong chỉ mục. Điều này cho phép chỉ mục quét, vì vậy bạn không cần truy cập vào bảng.

    2: Nếu bạn được cấp phép cho Chẩn đoán và Điều chỉnh, bạn có thể buộc kế hoạch quét bỏ qua với Quản lý Kế hoạch SQL

    THÊM

    PS - tài liệu bạn đã trích dẫn có từ 9i. Đó là già thực sự. Tôi muốn gắn bó với một cái gì đó gần đây


    Là một truy vấn với select count (distinct few_vals || ':' || many_vals || ':' || lots_vals )thực sự phổ biến? Không phải Oracle cho phép cú pháp select count (distinct few_vals, many_vals, lots_vals )- không thực hiện bất kỳ phép nối chuỗi nào, không cần các cột là kiểu văn bản và không dựa vào sự vắng mặt của :ký tự?
    ypercubeᵀᴹ

    @ ypercubeᵀᴹ bạn không thể làm count ( distinct x, y, z )trong Oracle. Vì vậy, bạn cần phải thực hiện một truy vấn con riêng biệt và đếm kết quả hoặc ghép nối như trên. Tôi chỉ làm điều đó ở đây để buộc một truy cập bảng (chứ không phải là chỉ số duy nhất quét) và chỉ có một dòng trong kết quả
    Chris Saxon

    1

    Có nhiều yếu tố truy vấn đóng góp vào quyết định cuối cùng về việc Chỉ số tổng hợp nên bắt đầu bằng gì và / hoặc chứa bên cạnh tính chọn lọc của cột.

    ví dụ:

    1. loại toán tử truy vấn nào đang được sử dụng: Nếu các truy vấn có toán tử như
      ">,> =, <, <="
    2. Có bao nhiêu hàng thực tế được mong đợi như là kết quả của truy vấn: Kết quả truy vấn sẽ là hầu hết các hàng từ bảng.
    3. Có bất kỳ chức năng nào đang được sử dụng trên cột bảng trong mệnh đề Where: Nếu truy vấn có bất kỳ chức năng UPPER, LOWER, TRIM, SUBSTRING được sử dụng trên cột đang được sử dụng trong điều kiện WHERE.

    chưa tiếp tục cuộc trò chuyện có liên quan, câu trả lời dưới đây của tôi áp dụng cho tình huống sau:

    1. "90% loại truy vấn trên một bảng đã cho có Mệnh đề WHERE với toán tử ="
    2. "nhiều nhất là truy vấn đang trả về 10% tổng số hàng trong bảng là kết quả"
    3. "không có loại hàm nào đang được sử dụng trên cột bảng trong mệnh đề WHERE"
    4. "hầu hết các cột thời gian trong Điều khoản WHERE được sử dụng chủ yếu là số loại,
      chuỗi"

    Theo kinh nghiệm của tôi, đó là cả DBA nên lưu tâm.

    Hãy tưởng tượng một quy tắc duy nhất đang được áp dụng:

    1) Nếu tôi tạo chỉ mục với hầu hết các cột chọn lọc nhưng cột đó không thực sự được sử dụng bởi hầu hết các truy vấn trên bảng đó hơn là không sử dụng cho công cụ db.

    2) Nếu tôi tạo một chỉ mục với cột được sử dụng rộng rãi nhất trong truy vấn là đầu tiên trong chỉ mục nhưng cột có độ chọn lọc thấp hơn thì hiệu năng truy vấn của tôi sẽ không tốt.

    Tôi sẽ liệt kê các cột được sử dụng chủ yếu trong 90% các truy vấn bảng. Sau đó, đặt những thứ đó theo thứ tự của hầu hết các cardinality đến ít cardinality.

    Chúng tôi sử dụng các chỉ mục để cải thiện hiệu suất truy vấn đọc và quy trình công việc đó (các loại truy vấn đọc) chỉ nên thúc đẩy việc tạo chỉ mục. Trong thực tế, khi dữ liệu tăng (hàng tỷ hàng) chỉ mục nén có thể lưu bộ nhớ nhưng chắc chắn làm tổn thương hiệu năng truy vấn đọc.


    1

    Về lý thuyết, cột chọn lọc nhất mang lại kết quả tìm kiếm nhanh nhất. Nhưng trong công việc tôi chỉ vấp phải một tình huống trong đó chúng ta có một chỉ số tổng hợp gồm 3 phần với phần được chọn nhiều nhất trước tiên. (ngày, tác giả, công ty xuất bản cho biết, theo thứ tự đó, bảng theo dõi ngón tay cái trên các bài đăng) và tôi có một truy vấn sử dụng cả 3 phần. Mysql mặc định sử dụng chỉ mục onlny của tác giả bỏ qua chỉ mục tổng hợp có chứa công ty và ngày mặc dù chúng có mặt trong truy vấn của tôi. Tôi đã sử dụng chỉ số lực để sử dụng hỗn hợp và truy vấn thực sự chạy chậm hơn. Tại sao điều đó xảy ra? Tôi sẽ nói với bạn:

    Tôi đã chọn một phạm vi vào ngày, vì vậy mặc dù ngày đó có tính chọn lọc cao, nhưng thực tế là chúng tôi đang sử dụng phạm vi đó để quét phạm vi (mặc dù phạm vi tương đối ngắn, 6 tháng trong số 6 năm dữ liệu) đã khiến tổng hợp có hại cho mys. Để sử dụng tổng hợp trong trường hợp cụ thể đó, mysql phải lấy tất cả các bài báo được viết từ những năm mới sau đó đi sâu vào việc tác giả là ai, và cho rằng tác giả đã không viết nhiều bài báo so với các tác giả khác, mysql thích tìm tác giả đó .

    Trong một trường hợp khác, truy vấn chạy nhanh hơn nhiều trên tổng hợp, trường hợp là khi một tác giả cực kỳ nổi tiếng và sở hữu hầu hết các hồ sơ, sắp xếp theo ngày có ý nghĩa. Nhưng mysql không tự động phát hiện trường hợp đó, tôi đã buộc chỉ số ... Vì vậy, bạn biết đấy, nó thay đổi. Quét phạm vi có thể làm cho cột chọn lọc của bạn vô dụng. Việc phân phối dữ liệu có thể khiến các trường hợp các cột được lựa chọn nhiều hơn cho các bản ghi khác nhau ...

    Những gì tôi sẽ làm khác là thay đổi ngày (một lần nữa, về mặt lý thuyết là chọn lọc nhất) sang bên phải, vì tôi biết tôi sẽ thực hiện quét phạm vi trên đó ngay bây giờ và điều đó tạo ra sự khác biệt.


    1
    Nếu truy vấn của bạn có một cái gì đó giống như WHERE (date BETWEEN @x AND @y) AND (author = @a) AND (publishing company = @p)sau đó một chỉ mục trên (author, publishing_company, date)hoặc trên (publishing_company, author, date)sẽ tốt hơn và sẽ được sử dụng - mà không buộc nó.
    ypercubeᵀᴹ

    -2

    Các trường hợp khác nhau cho các tình huống khác nhau. Biết mục tiêu của bạn; sau đó tạo các chỉ mục của bạn và chạy các kế hoạch giải thích cho từng kế hoạch và bạn sẽ có câu trả lời tốt nhất cho tình huống của mình.


    -2

    Từ thứ tự Cột trong Chỉ mục trên Hỏi Tom:

    Vì vậy, thứ tự các cột trong chỉ mục của bạn phụ thuộc vào CÁCH SỐ LƯỢNG CỦA BẠN được viết. Bạn muốn có thể sử dụng chỉ mục cho càng nhiều truy vấn càng tốt (để cắt giảm hơn tất cả số lượng chỉ mục bạn có) - điều đó sẽ điều khiển thứ tự của các cột. Không có gì khác (tính chọn lọc của a hoặc b hoàn toàn không được tính).

    Đồng ý rằng chúng ta phải sắp xếp các cột dựa trên mệnh đề where, nhưng câu lệnh "(độ chọn lọc của a hoặc b hoàn toàn không được tính)" là không chính xác.) ". Các cột được chọn nhiều nhất sẽ được dẫn đầu nếu nó được thỏa mãn vai trò đầu tiên ("mệnh đề where")

    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.