2015-11-10 2 views
0

Я пытаюсь написать запрос, который извлекает только первую (случайную) строку при выполнении условия.Избегайте полного сканирования таблицы - Извлеките только первую строку

-- Create table 
create table TRANSACTIONS_SAMPLE 
(
    institution_id    NUMBER(5) not null, 
    id       NUMBER(10) not null, 
    partitionkey     NUMBER(10) default 0 not null, 
    cardid      NUMBER(10), 
    accountid     NUMBER(10), 
    batchid      NUMBER(10) not null, 
    amt_bill      NUMBER(16,3), 
    load_date     DATE not null, 
    trxn_date     DATE not null, 
    single_msg_flag    NUMBER(5), 
    authaccounttype    VARCHAR2(2 BYTE), 
    originator     VARCHAR2(50), 
    amount      NUMBER(16,3) default 0.000 not null, 
    embeddedfee     NUMBER(16,3) default 0.000 not null,, 
    valuedate     DATE, 
    startofinterest    DATE, 
    minduevaluedate    DATE, 
    postdate      DATE, 
    posttimestamp    DATE, 
    Status      CHAR(4 BYTE) default 'NEW' not null, 
) 
partition by list (PARTITIONKEY) 
(
    partition 0002913151 values (1234567) 
    tablespace LIVE 
    pctfree 10 
    initrans 16 
    maxtrans 255 
    storage 
    (
     initial 8M 
     next 1M 
     minextents 1 
     maxextents unlimited 
    ) 
); 

-- Create/Recreate indexes 
create index TRANSACTIONS_SAMPLEI01 on TRANSACTIONS_SAMPLE (ACCOUNTID) 
    local; 
create index TRANSACTIONS_SAMPLEI02 on TRANSACTIONS_SAMPLE (LOAD_DATE) 
    local; 
create index TRANSACTIONS_SAMPLEI03 on TRANSACTIONS_SAMPLE (BATCHID) 
    local; 
create index TRANSACTIONS_SAMPLEI04 on TRANSACTIONS_SAMPLE (POSTDATE) 
    local; 
create index TRANSACTIONS_SAMPLEI05 on TRANSACTIONS_SAMPLE (POSTTIMESTAMP) 
    local; 
create index TRANSACTIONS_SAMPLEI06 on TRANSACTIONS_SAMPLE (STATUS, PARTITIONKEY) 
    local; 
create index TRANSACTIONS_SAMPLEI07 on TRANSACTIONS_SAMPLE (CARDID, TRXN_DATE) 
    local; 
create unique index TRANSACTIONS_SAMPLEUI01 on TRANSACTIONS_SAMPLE (ID, PARTITIONKEY) 
    local; 
-- Create/Recreate primary, unique and foreign key constraints 
alter table TRANSACTIONS_SAMPLE 
    add constraint TRANSACTIONS_SAMPLEPK primary key (ID, PARTITIONKEY); 

--QUERY 
Select * From (
Select t.AccountId From Transactions_sample t Group by t.Accountid Having Count(t.AccountId) > 10 order by dbms_random.random) 
Where Rownum = 1 

Проблема С этим запросом выполняется полное сканирование таблицы. Я хочу достичь тех же результатов без полного доступа к таблице. Есть идеи?

Благодаря

+1

Несомненно, вам нужно посмотреть каждую строку, чтобы получить счет, прежде чем вы сможете свести к одной случайной строке? Ожидаете ли вы полного сканирования индекса (TRANSACTIONS_SAMPLEI01), а не полного сканирования таблицы? Если ваша статистика обновлена, то это может привести к ее недействительности, поскольку она может рассчитывать значения. –

ответ

2

Вы можете получить его до полного сканирования индекса, используя TRANSACTIONS_SAMPLEI01, если добавить фильтр для where AccountId is not null. Но только если вы не хотите считать нулевые значения, конечно.

Столбец имеет значение NULL, но индекс не содержит нулевых значений. Чтобы включить счетчик нулей, он должен выполнить полное сканирование таблицы, потому что он не может получить этот счет из индекса. Если у вас есть этот фильтр, оптимизатор знает, что все значения идентификатора учетной записи должны быть в индексе, поэтому он должен ссылаться только на это, а не на таблицу.

explain plan for 
Select * From (
Select t.AccountId From Transactions_sample t where AccountId is not null Group by t.Accountid Having Count(t.AccountId) > 10 order by dbms_random.random) 
Where Rownum = 1; 

select * from table(dbms_xplan.display); 

PLAN_TABLE_OUTPUT                                              
--------------------------------------------------------------------------------------------------------------------- 
Plan hash value: 381125580                                            

---------------------------------------------------------------------------------------------------------------------                     
| Id | Operation     | Name     | Rows | Bytes | Cost (%CPU)| Time  | Pstart| Pstop |                     
---------------------------------------------------------------------------------------------------------------------                     
| 0 | SELECT STATEMENT   |      |  1 | 13 |  0 (0)| 00:00:01 |  |  |                     
|* 1 | COUNT STOPKEY    |      |  |  |   |   |  |  |                     
| 2 | VIEW      |      |  1 | 13 |  0 (0)| 00:00:01 |  |  |                     
|* 3 | SORT ORDER BY STOPKEY |      |  1 | 13 |  0 (0)| 00:00:01 |  |  |                     
|* 4 |  FILTER     |      |  |  |   |   |  |  |                     
| 5 |  SORT GROUP BY NOSORT |      |  1 | 13 |  0 (0)| 00:00:01 |  |  |                     
| 6 |  PARTITION LIST SINGLE|      |  1 | 13 |  0 (0)| 00:00:01 |  1 |  1 |                     
|* 7 |  INDEX FULL SCAN  | TRANSACTIONS_SAMPLEI01 |  1 | 13 |  0 (0)| 00:00:01 |  1 |  1 |                     
---------------------------------------------------------------------------------------------------------------------                     

Predicate Information (identified by operation id):                                      
---------------------------------------------------                                      

    1 - filter(ROWNUM=1)                                             
    3 - filter(ROWNUM=1)                                             
    4 - filter(COUNT("T"."ACCOUNTID")>10)                                         
    7 - filter("ACCOUNTID" IS NOT NULL)                                         

Note                                                  
-----                                                 
    - dynamic sampling used for this statement (level=2)                                     

В качестве альтернативы, если столбец можно сделать не-нулевым, тогда фильтр не потребуется.

+0

Спасибо за разъяснение. У меня есть еще один дополнительный вопрос. Скажем, что я должен был присоединиться к таблице транзакций со вторичной таблицей (учетными записями). Таблица Учетная запись содержит 3 идентификатора столбца, статус и баланс. Идентификатор столбца (уникальный) и статус обнуляются и индексируются. Как избежать полного сканирования таблицы счетов? Выберите * From ( ) Выберите t.AccountId From Transactions_sample t, учетные записи a Где t.accountid не является нулевым, а t.accountid = a.id и a.status = 'ОТКРЫТО' Группа по t.Accountid Имея счетчик (t .AccountId)> 10 order by dbms_random.random) Где Rownum = 1 – MrM

+0

@ user3651825 - если «статус» не проиндексирован, вы действительно не можете; ну, вы можете иметь индексный поиск, основанный на «t.accountid» как условие соединения, но вы все равно смотрите на каждую строку в 't', чтобы она была медленнее, чем FTS. И если у вас не будет небольшой доли открытых счетов (например, 5%, что кажется маловероятным), скорее всего, не будет более быстрой фильтрация на этом ранее. –

+0

@ user3651825 - и это зависит от того, действительно ли это повлияет на ваши тайминги. Иногда FTS - лучший выбор, и похоже, что он здесь. Вы * можете * получить свой подмножество всех идентификаторов учетных записей, которые имеют более 10 строк; присоедините это к вашей таблице 'account'; фильтровать статус; и примените порядок-by и rownum к *, который * уменьшил набор результатов. Но опять-таки доля учетных записей, которые будут соответствовать, может сделать FTS правильным выбором. Похоже, вы направляетесь в область преждевременной оптимизации - исправляете проблему, которую, как вы думаете, можете иметь, но которая не является реальной. Трудно сказать. –

Смежные вопросы