Таблицы хранятся в блоках построчно. Чем меньше суммарный объём полей в записях, тем больше записей помещается в одном блоке.
При чтении какой-либо записи Oracle берёт с диска (или из кеша) весь блок, в котором находится эта запись.
При необходимости перебрать, например, все значения одного поля таблицы, надо прочесть все соответствующие блоки. Предположим, что таблица большая и не помещается в кеш. Тогда, при наличии в таблице «посторонних» неиспользуемых в этом запросе полей, Oracle будет считывать большее количество блоков для получения того же результата.
Пример на Oracle 11:
create table a (n number, s varchar2(4000));Хранения «по колонкам» в Oracle не предусмотрено. Для лучшего быстродействия следует избегать объединения в одной таблице полей, которые могут быть востребованы по отдельности.
create table b (n number);
begin
for i in 1..1000000 loop
insert into a values(i, lpad('a', 4000, 'a'));
insert into b values(i);
end loop;
end;
set timing on;
select sum(n) from a;
SUM(N)
----------
5.0000E+11
Elapsed: 00:02:04.51
select sum(n) from b;
SUM(N)
----------
5.0000E+11
Elapsed: 00:00:00.11
4 комментария:
create index i on a(n)
Да, это годится для данного примера, но не меняет дела в принципе. И не поможет в случаях, когда записи выбираются не подряд, а по списку значений другого индексированного поля, или по списку ROWID, который вернул внешний поисковый движок.
Есть возможность индексного hash join на одной таблице, не уверен что это сработает с доменным индексом.
drop table a;
create table a (n1 number not null, n2 number not null, s varchar2(4000));
insert into a select level, level, lpad('x',4000,'x') from dual connect by level < 100000;
commit;
create index i1 on a(n1);
create index i2 on a(n2);
begin
dbms_stats.gather_table_stats(user, 'A', estimate_percent => null, cascade => true);
end;
/
explain plan for
select n1, n2 from a;
select * from table(dbms_xplan.display);
| 0 | SELECT STATEMENT |
| 1 | VIEW | index$_join$_001
|* 2 | HASH JOIN |
| 3 | INDEX FAST FULL SCAN| I1
| 4 | INDEX FAST FULL SCAN| I2
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access(ROWID=ROWID)
Да, это годится для вашего примера (хотя FULLSCAN всей таблицы, если в ней нет лишнего поля "s", всё равно быстрее) но не меняет дела в принципе :) и не будет работать для случаев, когда интересующее нас поле является BLOB-ом или CLOB-ом. Для доменного индекса тоже не сработает, видимо.
Отправить комментарий