Здравствуйте, B0rG, Вы писали:
BG>Ну дык, так о чем мы тогда говорим то?
Да похоже каждый о своем уже.
Резюмирую сказанное и показанное мною: для нескольких запросов, отличающихся только списком выборки (select ...) и одинаковых в остальных частях (from, where и т.д.) оптимальные планы выполнения также могут отличаться. И разница во времени выполнения и потребляемых ресурсах может быть весьма существенна.
Из этого, в частности следует, что в запросе нужно явно перечислять только необходимые столбцы, а не писать бездумно select * потому что "один фиг выполняться будет одинаково".
Здравствуйте, Аноним, Вы писали: А>Разница от того, что Ораклу для count(*) надо всё-таки данные перебрать все чтобы получить точное количество результирующих записей, а для пары-тройки несортированых записей скорость на порядок быстрее.
Нет никакой разницы, count(*) или count(1). Это все urban legend миллион раз опровергнутые. Execution plan пбсолютно одинаков, к тому же
в каждой1 второй книжке по оптимизации постоянно пишут, что скорость выборки не зависит от количества полей перечисляемых в запросе.
Проблема такая.
Есть база oracle. Есть прилада. Прилада выводит большое количество данных в постраничном режиме. При этом пользователь очень-очень хочет видеть не просто "вперед-назад" — а сколько в точности есть записей и сколько еще страниц осталось.
В результате используется count на данные по тому фильтру который наложил пользователь и показ одной текущей страницы для пользователя.
Результат. Разница между выборкой одной страницы и выполнением count — на несколько порядков.
(по относительно крупной таблице по достаточно "общему" фильтру получается вывод одной страницы занимает где-то в пределах сотой доли секунды, count — 5-10 секунд)
Быстродействие в результате ни к черту. Но заказчик твердо хочет видеть число записей, удовлетворяющих фильтру.
Можно ли как-то ускорить подсчет количества данных, удовлетворяющих фильтру? Индексы на поля, по которым фильтр проводится — наложены.
Здравствуйте, fmiracle, Вы писали:
F>Проблема такая. F>Есть база oracle. Есть прилада. Прилада выводит большое количество данных в постраничном режиме. При этом пользователь очень-очень хочет видеть не просто "вперед-назад" — а сколько в точности есть записей и сколько еще страниц осталось.
F>В результате используется count на данные по тому фильтру который наложил пользователь и показ одной текущей страницы для пользователя.
F>Результат. Разница между выборкой одной страницы и выполнением count — на несколько порядков. F>(по относительно крупной таблице по достаточно "общему" фильтру получается вывод одной страницы занимает где-то в пределах сотой доли секунды, count — 5-10 секунд)
F>Быстродействие в результате ни к черту. Но заказчик твердо хочет видеть число записей, удовлетворяющих фильтру.
F>Можно ли как-то ускорить подсчет количества данных, удовлетворяющих фильтру? Индексы на поля, по которым фильтр проводится — наложены.
Здравствуйте, fmiracle, Вы писали:
F>пользователь очень-очень хочет видеть не просто "вперед-назад" — а сколько в точности есть записей и сколько еще страниц осталось.
Желание обоснованное (бизнес-процессом) или аргументы типа "почему Access может а вы нет"?
F>(по относительно крупной таблице по достаточно "общему" фильтру получается вывод одной страницы занимает где-то в пределах сотой доли секунды, count — 5-10 секунд) F>Быстродействие в результате ни к черту. Но заказчик твердо хочет видеть число записей, удовлетворяющих фильтру.
Если 5-10 секунд для заказчика приемлемы, то делайте count.
F>Можно ли как-то ускорить подсчет количества данных, удовлетворяющих фильтру? Индексы на поля, по которым фильтр проводится — наложены.
Кардинально нет. Можно использовать аналитику (count over) и обойтись одним запросом. Заодно и результаты будут согласованными, в отличие от отдельного count.
Здравствуйте, sunsquirel, Вы писали:
S>Скажите, а Вы делаете count(*) или как?
count(*)
Re: Можно ли ускорить count в Oracle?
От:
Аноним
Дата:
11.04.08 04:40
Оценка:
Нужно посмотреть explain plan, используются ли индексы вообще? Какой медод доступа к базе (ADO, OO4O) ?
Разница от того, что Ораклу для count(*) надо всё-таки данные перебрать все чтобы получить точное количество результирующих записей, а для пары-тройки несортированых записей скорость на порядок быстрее.
По моему опыту, OO4O работает со страницами гораздо лучше. Смотреть тут http://www.orafaq.com/faqoo4o.htm
В зависимости от количества данных и предназначения запроса может иметь смысл огранизовать специальную таблицу в которой будут собираться все интересующие записи, готовые к выводу на экран. И уже на эту таблицу накладывать фильтры, считать количество записей и т.д.
F>Быстродействие в результате ни к черту. Но заказчик твердо хочет видеть число записей, удовлетворяющих фильтру.
а индекс на таблице есть?
может hiwatermark высоко задран и таблицу нужно реорганизовать?
сколько всего строк в таблице?
Здравствуйте, JazzzMaster, Вы писали:
N>>может hiwatermark высоко задран и таблицу нужно реорганизовать? JM>кстати, интересно, а можно ли его как-нибудь "понизить" не используя truncate ?
Здравствуйте, krot_av, Вы писали:
_>Нет никакой разницы, count(*) или count(1). Это все urban legend миллион раз опровергнутые.
К чему здесь этот флуд? Никто не предлагал count(1).
_>скорость выборки не зависит от количества полей перечисляемых в запросе.
А это неверно.
Здравствуйте, wildwind, Вы писали:
_>>скорость выборки не зависит от количества полей перечисляемых в запросе. W>А это неверно.
Execution plan будет одинаковым, вся разница только в передаваемых объемах данных по сети.
Здравствуйте, krot_av, Вы писали:
_>>>скорость выборки не зависит от количества полей перечисляемых в запросе. W>>А это неверно. _>Execution plan будет одинаковым, вся разница только в передаваемых объемах данных по сети.
И это неверно. Подумай об индексах.
Здравствуйте, wildwind, Вы писали:
W>И это неверно. Подумай об индексах.
Использование индексов зависит не от полей перечисленных в select, а от условий WHERE.
Так что никакого влияние на индексы select * или select some field не окажет, да и не должен оказывать.
Здравствуйте, krot_av, Вы писали:
W>>И это неверно. Подумай об индексах. _>Использование индексов зависит не от полей перечисленных в select, а от условий WHERE. _>Так что никакого влияние на индексы select * или select some field не окажет, да и не должен оказывать.
Не упорствуй в своем заблуждении. Сравни планы для "select pk from table" и "select * from table" для обычной (heap) таблицы.
W>Не упорствуй в своем заблуждении. Сравни планы для "select pk from table" и "select * from table" для обычной (heap) таблицы.
Я их сравнивал в оракл и DB2.
Если говоритиь о заблуждениях, то будет тебе известно, что для приведенных тобой запросов будет использован full scan в любом случае.
Здравствуйте, krot_av, Вы писали:
_>Здравствуйте, wildwind, Вы писали:
W>>Не упорствуй в своем заблуждении. Сравни планы для "select pk from table" и "select * from table" для обычной (heap) таблицы.
_>Я их сравнивал в оракл и DB2.
Продемонстрируй! Или просто скажи что проверять было лень.
Вот мой пример:
SQL> create table test_tab as select rownum id, rpad('*', 2000, '*') text from all_objects;
Таблица создана.
SQL> alter table test_tab add constraint test_tab_pk primary key (id);
Таблица изменена.
SQL> exec dbms_stats.gather_table_stats(user, 'test_tab', cascade => true)
Процедура PL/SQL успешно завершена.
SQL> set autotrace traceonly
SQL> set timing on
SQL> select * from test_tab;
83692 строк выбрано.
Затрач.время: 00:00:09.34
План выполнения
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=8264 Card=83692 Bytes=167802460)
1 0 TABLE ACCESS (FULL) OF 'TEST_TAB' (Cost=8264 Card=83692 Bytes=167802460)
Статистика
----------------------------------------------------------
0 recursive calls
0 db block gets
83706 consistent gets
83692 physical reads
0 redo size
1274661 bytes sent via SQL*Net to client
61730 bytes received via SQL*Net from client
5581 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
83692 rows processed
SQL> select id from test_tab;
83692 строк выбрано.
Затрач.время: 00:00:05.93
План выполнения
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=40 Card=83692 Bytes=418460)
1 0 INDEX (FAST FULL SCAN) OF 'TEST_TAB_PK' (UNIQUE) (Cost=40 Card=83692 Bytes=418460)
Статистика
----------------------------------------------------------
0 recursive calls
0 db block gets
5915 consistent gets
357 physical reads
0 redo size
949057 bytes sent via SQL*Net to client
61730 bytes received via SQL*Net from client
5581 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
83692 rows processed
SQL> disc
Отсоединено от Oracle9i Enterprise Edition Release 9.2.0.7.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.7.0 - Production
_>Если говоритиь о заблуждениях, то будет тебе известно, что для приведенных тобой запросов будет использован full scan в любом случае.
full scan он разный бывает.
Здравствуйте, Neco, Вы писали:
JM>>кстати, интересно, а можно ли его как-нибудь "понизить" не используя truncate ? N>alter table move?
а для индексов — alter index rebuild tablespace
Здравствуйте, wildwind, Вы писали:
_>>Если говоритиь о заблуждениях, то будет тебе известно, что для приведенных тобой запросов будет использован full scan в любом случае. W>full scan он разный бывает.
Странно, но мне то же самое поведение смоделировать не удалось. В обоих случаях случаях был использован full scan
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'T1'
Oracle правда восьмой
SQL> select banner from v$version;
BANNER
----------------------------------------------------------------
Oracle8i Enterprise Edition Release 8.1.7.4.0 — Production
PL/SQL Release 8.1.7.4.0 — Production
CORE 8.1.7.0.0 Production
TNS for Solaris: Version 8.1.7.4.0 — Production
NLSRTL Version 3.4.1.0.0 — Production
_>в каждой1 второй книжке по оптимизации постоянно пишут, что скорость выборки не зависит от количества полей перечисляемых в запросе.
если идет сканирование по индексу и все поля в кляузе select входят в этот индекс, то, разумеется, такой запрос будет отрабатывать эффективнее, т.к. позволяет брать данные напрямую из индекса, избегая, например, table access by rowid для Oracle(либо аналогов для других СУБД)
Здравствуйте, JazzzMaster, Вы писали:
JM>Странно, но мне то же самое поведение смоделировать не удалось. В обоих случаях случаях был использован full scan
Возможно при выборке уникальных ключей оркал научился использовать только данные индекса.
В любом случае count(1) = count(*), любой нормальный оптимизатор их будет считать одинаково.
Здравствуйте, Ziaw, Вы писали:
Z>Возможно при выборке уникальных ключей оркал научился использовать только данные индекса. Z>В любом случае count(1) = count(*), любой нормальный оптимизатор их будет считать одинаково.
тьфу, понял свой косяк — не собрал статистику по созданной таблице
Здравствуйте, Ziaw, Вы писали:
Z>Возможно при выборке уникальных ключей оркал научился использовать только данные индекса.
уникальность ключа здесь не имеет значения
данные, действительно, можно получить только из индекса, избегая чтения таблицы
но в случае select id from some_table выигрыша от использования индекса, разумеется, не будет
Здравствуйте, wildwind, Вы писали:
W>Почему же не будет, я ведь продемонстрировал это выше. Выигрыш будет, если индекс ощутимо меньше таблицы по размеру.
Вы сравнивали "select * " с "select pk "
сравнение, на мой взгляд, некорректное, ибо эти выборки возвращают, в общем случае, различный результат
повторюсь: в случае с "select pk " index FFS и FTS будут равноэффективны, только в первом случае юудет чтение индекса, а во втором — таблицы, соответственно
Здравствуйте, Niteshade, Вы писали:
N>Вы сравнивали "select * " с "select pk " N>сравнение, на мой взгляд, некорректное, ибо эти выборки возвращают, в общем случае, различный результат
Ты наверное не прочитал всю тему; этим сравнением я иллюстрировал ошибочность утверждения krot_av, что план и эффективность запроса не зависят от полей, перечисленных в выборке.
N>повторюсь: в случае с "select pk " index FFS и FTS будут равноэффективны, только в первом случае юудет чтение индекса, а во втором — таблицы, соответственно
Если ты по-прежнему не видишь разницы между чтением таблицы в 145 Мб и индекса в 2 Мб, то не поленись и проделай эксперименты сам.
Здравствуйте, wildwind, Вы писали:
N>>повторюсь: в случае с "select pk " index FFS и FTS будут равноэффективны, только в первом случае юудет чтение индекса, а во втором — таблицы, соответственно
W>Если ты по-прежнему не видишь разницы между чтением таблицы в 145 Мб и индекса в 2 Мб, то не поленись и проделай эксперименты сам.
На мой взгляд без WHERE или ORDER BY этот спор особого значения не имеет. План скажет full index scan, но базе все равно придется высосать всю таблицу.
Здравствуйте, Niteshade, Вы писали:
N>Здравствуйте, Ziaw, Вы писали:
Z>>Возможно при выборке уникальных ключей оркал научился использовать только данные индекса. N>уникальность ключа здесь не имеет значения N>данные, действительно, можно получить только из индекса, избегая чтения таблицы
вы правы, для оракла важно будет nullable поле или нет, null он не индексирует.
N>но в случае select id from some_table выигрыша от использования индекса, разумеется, не будет
а вот это очень странное утверждение, откуда вывод? тем более разумеется...
Важны количество прочитанных блоков и степень фрагментированности индекса и таблицы, в общем случае данные в таблице будут более разбросаны и чтений понадобится больше.
Здравствуйте, wildwind, Вы писали:
BG>>План скажет full index scan, но базе все равно придется высосать всю таблицу. W>C какой стати? Продемонстрируй! W>P.S. Случаи, когда результат команды explain plan отличается от реального плана, известны, но сейчас речь не о них, надеюсь.
Не, не о том.
утрированно: выполнение запроса состоит из двух шагов: построение плана (его оптимизация и т.д.) и собственно процесс выборки данных ("высасывания данных").
без where или order сравнивать запросы select * и select id особого смысла не имеет, т.к. высосать придется все данные в любом случае, и особых выигрышей мы не получим.
Другое дело сравнивать запросы вида:
select * from t where ID between 100 000 000 and 101 000 000
и
select * from t where to_char(id) like '1%'
тут выигрыши видны невооруженным глазом.
Здравствуйте, B0rG, Вы писали:
BG>без where или order сравнивать запросы select * и select id особого смысла не имеет, т.к. высосать придется все данные в любом случае, и особых выигрышей мы не получим.
Похоже, ты плохо представляешь, как хранятся и извлекаются данные. Почитай про организацию индексов, про пути доступа, попробуй сам выполнять такие запросы и, как ты говоришь, "выигрыш станет виден невооруженным глазом".
/
5901540 строк выбрано.
Затрач.время: 00:01:40.44
Статистика
----------------------------------------------------------
1 recursive calls
0 db block gets
71614 consistent gets
12695 physical reads
0 redo size
64209469 bytes sent via SQL*Net to client
649499 bytes received via SQL*Net from client
59017 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
5901540 rows processed
--==============================
/
5901540 строк выбрано.
Затрач.время: 00:07:38.10
Статистика
----------------------------------------------------------
1499 recursive calls
0 db block gets
127347 consistent gets
68535 physical reads
0 redo size
710351872 bytes sent via SQL*Net to client
649499 bytes received via SQL*Net from client
59017 SQL*Net roundtrips to/from client
108 sorts (memory)
0 sorts (disk)
5901540 rows processed
Хотя и без экспериментов очевидно, что чем больше объем данных, которые надо прочитать, тем больше времени на это уйдёт.
А с where и group by все как раз сложнее и менее очевидно, т.к. гораздо больше факторов играют роль.
Здравствуйте, wildwind, Вы писали:
W>Похоже, ты плохо представляешь, как хранятся и извлекаются данные. Почитай про организацию индексов, про пути доступа, попробуй сам выполнять такие запросы и, как ты говоришь, "выигрыш станет виден невооруженным глазом".
хммм... интресно что вас заставило сделать такое утверждение.
W>Хотя и без экспериментов очевидно, что чем больше объем данных, которые надо прочитать, тем больше времени на это уйдёт.
Ну дык, так о чем мы тогда говорим то?
только о том, что для SQL> select id from test_tab;
План выполнения
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=40 Card=83692 Bytes=418460)
1 0 INDEX (FAST FULL SCAN) OF 'TEST_TAB_PK' (UNIQUE) (Cost=40 Card=83692 Bytes=418460)
и для
SQL> select * from test_tab;
План выполнения
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=8264 Card=83692 Bytes=167802460)
1 0 TABLE ACCESS (FULL) OF 'TEST_TAB' (Cost=8264 Card=83692 Bytes=167802460)
просто так из любопытства посмотрите план для
select id, text from test_tab
(я только картиночный план могу видеть).
на моей десятке план такой же как и для select *, что в общем не удивительно, ведь если мы просим только индексируемое поле, то почему бы и не отдать только индексируемое поле, а если мы делаем select * вместе с индексируемым полем, но index scan нах не нужен, потому как все равно надо отдавать full table. О чем я собственно и говорил — без where, order by или group by спор будет несколько страннен.
W>А с where и group by все как раз сложнее и менее очевидно, т.к. гораздо больше факторов играют роль.
зато гораздо интереснеее... планы запросов для вашей таблицы (возвращаясь к исходному count() )
select count(id) from test_tab; : index scan
select count(text) from test_tab : full table
select count(2) from test_tab where id between 1 000 and 2 000 : выдает index range scan палюбому хоть для
select count(text) from test_tab where id between 1 000 and 2 000
о чем нам это говорит, о великий знаток путей организаций идексов и путей доступа?
Здравствуйте, wildwind, Вы писали:
W>Ты наверное не прочитал всю тему; этим сравнением я иллюстрировал ошибочность утверждения krot_av, что план и эффективность запроса не зависят от полей, перечисленных в выборке.
поясню, если предыдущий пост был неверно понят: если поля, перечисленные в условии select, входят в индекс, по которому осуществляется доступ, то такой запрос, разумеется, будет эффективнее, т.к. позволит избежать обращения к таблице
W>Если ты по-прежнему не видишь разницы между чтением таблицы в 145 Мб и индекса в 2 Мб, то не поленись и проделай эксперименты сам.
пример, приведенный мной, был совершенно конкретный
если Вы сомневаетесь в его справедливости, приведите, пожалуйста, планы запросов, которые докажут обратное
причем здесь указанные Вами 145 и 10 Мб — непонятно)
указанные Вами ранее планы ни в коей мере не соотносятся с примером
Здравствуйте, Ziaw, Вы писали:
Z>Важны количество прочитанных блоков и степень фрагментированности индекса и таблицы
это справедливо
пример, конечно, относился к тому, что общий объем прочитанных данных будет одинаков
>в общем случае данные в таблице будут более разбросаны и чтений понадобится больше.
в общем случае, сложно сказать, что и как будет в таблице, организованной по куче)