Почему этот запрос такой медленный? - PullRequest
4 голосов
/ 03 июля 2010

У меня есть столы FOO и BAR.FOO имеет внешний ключ для PK BAR.

Когда я выполняю следующий запрос, это занимает несколько секунд.

select foo.name, foo.description, bar.quadrant from FOO, BAR
where FOO.BAR_ID = BAR.BAR_ID

Вот мой план объяснения:

OPERATION        OBJECT_NAME     OPTIONS     COST 
SELECT STATEMENT                                 39 
 HASH JOIN                                       39 
  TABLE ACCESS   BAR             FULL            2 
  TABLE ACCESS   FOO             FULL            36 

В FOO содержится 6000 записей, а в BAR только 5. Столбец BAR_ID - это НОМЕР.

Это выполняется в Oracle 10g, и для его завершения требуется ~ 3 секунды.Это кажется чрезвычайным, учитывая, как быстро он выполняет другие запросы.

EDIT определение таблицы:

CREATE TABLE BAR
 (
    "BAR_ID" NUMBER NOT NULL,
    "QUADRANT" VARCHAR2(100 BYTE) NOT NULL,
    CONSTRAINT "BAR_PK" PRIMARY KEY ("BAR_ID")
 )

 CREATE TABLE FOO
 (  "FOO_ID" NUMBER NOT NULL, 
    "BAR_ID" NUMBER NOT NULL, 
    "NAME" VARCHAR2(250 BYTE) NOT NULL, 
    "DESCRIPTION" VARCHAR2(250 BYTE),
    CONSTRAINT "FOO_PK" PRIMARY KEY ("FOO_ID"), 
    CONSTRAINT "FOO__FK1" FOREIGN KEY ("BAR_ID") REFERENCES BAR ("BAR_ID") ENABLE
 );

Ответы [ 6 ]

3 голосов
/ 03 июля 2010

Вы уверены, что у вас хорошая статистика? Я создал тестовый пример из вашего DDL и видел этот план перед статистикой:

--------------------------------------------------------------------------- 
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     | 
--------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT   |      |  4996 |  1619K|    10  (10)| 00:00:01 | 
|*  1 |  HASH JOIN         |      |  4996 |  1619K|    10  (10)| 00:00:01 | 
|   2 |   TABLE ACCESS FULL| BAR  |     5 |   325 |     3   (0)| 00:00:01 | 
|   3 |   TABLE ACCESS FULL| FOO  |  4996 |  1302K|     6   (0)| 00:00:01 | 
--------------------------------------------------------------------------- 

(Если вы получите вывод dbms_xplan, вы также увидите «динамическую выборку, используемую для этого оператора»).

После этого:

SQL> begin dbms_stats.gather_table_stats(user,'FOO'); end;
  2  /

PL/SQL procedure successfully completed.

SQL> c/FOO/BAR/
  1* begin dbms_stats.gather_table_stats(user,'BAR'); end;
SQL> /

PL/SQL procedure successfully completed.

Я вижу:

--------------------------------------------------------------------------------------- 
| Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     | 
--------------------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT             |        |  4996 |   131K|     9  (12)| 00:00:01 | 
|   1 |  MERGE JOIN                  |        |  4996 |   131K|     9  (12)| 00:00:01 | 
|   2 |   TABLE ACCESS BY INDEX ROWID| BAR    |     5 |    40 |     2   (0)| 00:00:01 | 
|   3 |    INDEX FULL SCAN           | BAR_PK |     5 |       |     1   (0)| 00:00:01 | 
|*  4 |   SORT JOIN                  |        |  4996 | 94924 |     7  (15)| 00:00:01 | 
|   5 |    TABLE ACCESS FULL         | FOO    |  4996 | 94924 |     6   (0)| 00:00:01 | 
--------------------------------------------------------------------------------------- 
2 голосов
/ 03 июля 2010

Получите TKPROF трассировку для вашего запроса, чтобы увидеть, что на самом деле происходит - explain plan - это только оценка.

В основном, выполните команду ALTER SESSION SET SQL_TRACE = TRUE перед запросом, выполните запрос, а затем ALTER SESSION SET SQL_TRACE = FALSE. Затем найдите файл трассировки, полученный из местоположения, определенного параметром USER_DUMP_DEST (см. Представление v$parameter). Используйте утилиту TKPROF для обработки необработанного файла трассировки в более читабельном формате и проверки результатов (и опубликуйте их здесь).

(См. Использование SQL Trace и TKPROF от Oracle.com для получения дополнительной информации.)

1 голос
/ 03 июля 2010

В Oracle встроено множество инструментов для исследования такого рода проблем.

Начните с этой статьи:

http://method -r.com / загрузки / doc_download / 10-для-разработчиков решений-друзей-с-оракула-БД-Cary-Millsap

0 голосов
/ 08 июля 2010

Весьма разумно выполнить полное сканирование таблицы в таблицу FOO, таблица имеет строку 4996, и вы задаете запрос, который вы задаете оракулу: «Отправьте все записи Foo вместе с их bar.quadrant»

0 голосов
/ 03 июля 2010

Насколько я помню, Oracle будет рассматривать это как простое объединение, которое будет игнорировать индексы.Основная идея заключается в том, что, поскольку вы не ограничиваете данные ни в одной из таблиц, а просто объединяете их, она считает, что полное сканирование таблицы будет работать лучше.Если в таблице foo есть ноль в столбце bar_id для нескольких строк, то вы можете использовать подсказку индекса.

Например, если вы выполните запрос, основанный на одном bar_id, план объяснения, скорее всего, будетиспользуйте индексы, как ожидалось.Без индекса будет выполнено полное сканирование таблицы баров, потому что оно очень мало, и полное сканирование таблицы foo, потому что вы не отфильтровываете значения bar_id.

Последнее замечание:убедитесь, что вы обновляете статистику по таблицам и индексам.Это было бы важно для разреженного индекса, поскольку Oracle может понять, что индекс может существенно изменить стоимость запроса.

0 голосов
/ 03 июля 2010

Таблица часто обновляется?

Является ли foo.description огромным CLOB?

Из-за задержек в сети кажется, что запрос занимает много времени?

Являются ли эти таблицы действительно сложными представлениями?

Были ли таблицы когда-то очень большими и с тех пор было удалено много данных?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...