За последние 24 часа нас посетили 20979 программистов и 1018 роботов. Сейчас ищут 523 программиста ...

Оптимизация запросов

Тема в разделе "Oracle Database", создана пользователем decoder, 17 апр 2009.

  1. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    Кто есть сведущий (знаю, есть такие :)), подскажите, как оптимизировать запросы к Ораклу?
    По работе дорабатываю и оптимизирую сейчас один сайт, который был сделан еще в 2001 или 2002-ом году. Изначально использовал Мускуль, потом переписали запросы для Оракла, но так, на скорую руку - лишь бы работало.
    Что сделал уже - индексы расставил, запросы из циклов убрал.

    Какие есть советы по оптимизации, которые касаются каких-то особенностей Оракла?
    Настройка сервера в это не входит, он настроен хорошо (по крайней мере другой проект на том же сервере отрабатывается в 3-4 раза быстрее).

    Спасибо :)
     
  2. Поставь спотлайт, в нем очень легко отловить медленные запросы - соответственно, их надо будет разобрать, и переписать.
     
  3. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    флоппик
    Спасибо. К сожалению, мне сказали (админ), что его нет смысла качать и ставить, так как это софт для настройки сервера, а не оптимизации запросов, а другой программер посоветовал использовать Quest Toad... чем теперь и пытаюсь заниматься...
     
  4. твой админ не прав. Это НЕ средство для настройки сервера. Это средство его мониторинга.
     
  5. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    флоппик
    Окей, дам ему ссылку, а то мне не поверит :)

    На самом деле после профилирования мы нашли проблемное место.
    Пришлось сначала поправить немного код и скорость увеличилась втрое. После двух дней оптимизации время сократили с 4.9 секунды до 1.09.

    Но все еще слишком медленно. Стали продолжать разбирать запрос в проблемном месте - оказалось дело в сортировке. Без нее запрос отрабатывается за 15 мсек, с ней - 515 мсек. Индекс на поле стоит (поле NUMBER).

    Олег, ты случайно не знаешь, в чем может быть дело.

    В таблице, собственно, не так много записей (около 32к).
     
  6. ну так ты хоть запрос покажи.... )))
     
  7. Еще покажи EXLPAIN PLAN для запроса
     
  8. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    Все, что от него осталось :)

    [sql]
    SELECT * FROM (
    SELECT "~".*, rownum "#" FROM (
    SELECT id
    FROM news
    WHERE BITAND(p_type, 2) <> 0
    AND lang_id=1
    AND (is_main IS NULL OR is_main != 1)
    ORDER BY cdate DESC
    ) "~"
    ) WHERE "#" > 0 and rownum <= 15[/sql]

    [sql]Plan
    SELECT STATEMENT ALL_ROWSCost: 2 896 Bytes: 390 Cardinality: 15
    6 COUNT STOPKEY
    5 VIEW NEW_TATAR. Cost: 2 896 Bytes: 27 378 Cardinality: 1 053
    4 COUNT
    3 VIEW NEW_TATAR. Cost: 2 896 Bytes: 13 689 Cardinality: 1 053
    2 SORT ORDER BY Cost: 2 896 Bytes: 21 060 Cardinality: 1 053
    1 TABLE ACCESS FULL TABLE NEW_TATAR.NEWS Cost: 2 896 Bytes: 21 060 Cardinality: 1 053
    [/sql]

    Время 15 и 515 мс без "шелухи", только для
    [sql]SELECT id
    FROM news
    WHERE BITAND(p_type, 2) <> 0
    AND lang_id=1
    AND (is_main IS NULL OR is_main != 1)
    ORDER BY cdate DESC
    [/sql]
     
  9. а поле cdate какого типа, и есть ли на нем индекс?
     
  10. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    Поле типа NUMBER, индекс стоит.
     
  11. Какая хранимая длина поля? 11 байт?
    Кстати, попробуй делать - [sql]alter session set optimizer_mode = 'ALL_ROWS';[/sql] перед запросом?
     
  12. либо наоборот,
    [sql]alter session set optimizer_mode='FIRST_ROWS_10';[/sql]
     
  13. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    Так точно, 11.

    Попробовал ALL_ROWS, без изменений.
     
  14. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    FIRST_ROWS_10 тоже попробовал.

    Время немного варьируется , но незначительно - в пределах 10 мс, наверное.
     
  15. о!
    Нука, а скажи мне что будет если
    [sql]SELECT id
    FROM news
    WHERE BITAND(p_type, 2) <> 0
    AND lang_id=1
    /* AND (is_main IS NULL OR is_main != 1) */
    ORDER BY cdate DESC[/sql]

    Сдается мне, что у тебя полное сканирование таблицы как раз изза is_main, т.к. он может быть NULL
     
  16. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    Снова незначительные колебания...

    Сразу скажу, что мы пробовали.

    Составные и простые индексы по полям where, написание своих функций и использование их в индексе и т. д. Все это давало либо совсем незаметный прирост производительности, либо время резко возрастало :)

    В итоге мы пришли как раз к сортировке, на которую до этого не обращали внимание (ну есть же индекс - и нормально должно быть).

    План без проверки is_main:
    [sql]
    Plan
    SELECT STATEMENT FIRST_ROWSCost: 2 896 Bytes: 18 954 Cardinality: 1 053
    2 SORT ORDER BY Cost: 2 896 Bytes: 18 954 Cardinality: 1 053
    1 TABLE ACCESS FULL TABLE NEW_TATAR.NEWS Cost: 2 896 Bytes: 18 954 Cardinality: 1 053
    [/sql]
     
  17. Странна, странна. Нипаняятна.
    Я бы попробовал сделать составной индекс, зафорсить использование индекса для сортировки (возможно и других) через /*+index */
     
  18. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    флоппик
    Спасибо :)

    Все, 18 часов вечера пятницы. Освобождаю свой мозг от этого дела до понедельника...
     
  19. decoder, мы тут посовещались, и вроде нашли решение:

    [sql]select *
    from ( select /*+ FIRST_ROWS(n) */
    a.*, ROWNUM rnum
    from ( SELECT id
    FROM news
    WHERE BITAND(p_type, 2) <> 0
    AND lang_id=1
    AND (is_main IS NULL OR is_main != 1)
    ORDER BY cdate DESC ) a
    where ROWNUM <=
    :MAX_ROW_TO_FETCH )
    where rnum >= :MIN_ROW_TO_FETCH;[/sql]

    Должно работать по крайней мере намного быстрее для первых страниц. Думаю, к последним правда будет падать эффективность.
     
  20. значение в хинт оптимайзера /*+ FIRST_ROWS(n) */ надо будет из скрипта тоже подставлять )
     
  21. decoder

    decoder Активный пользователь

    С нами с:
    11 фев 2006
    Сообщения:
    469
    Симпатии:
    0
    Прошу прощения, забыл ответить...
    Еще в ту пятницу попробовали. Так он выбирал все равно ALL_RAWS. Хинт, кажется, на строку выше пришлось переставить, тогда он заработал.
    Но, к сожалению, никаких результатов это не дало.
    Позже еще пришла мысль, что дело в том, что индекс стоит ASC, а выборка DESC. Что меня удивило, когда сделал и индекс DESC, то время увеличилось еще на 100мс.
    В общем, пока мы это дело отложили в сторону, 1с по сравнению с 4-6 - уже серьезный прогресс :)
    Спасибо за помощь!