http___blog.yavor.info__m_201010_2.xml
https___blog.yavor.info__m_201010_lang_en.xml
1.1 2.1 2.2 2.3 3.1 3.2 4.1 5.1 6.1 6.2 6.3 6.4 6.5 7.1 8.1 8.2 8.3 8.4 9.1 9.2 9.3 9.4 10.1 10.2 11.1 12.1 12.2 12.3 13.1 14.1 14.2 15.1 16.1 16.2 16.3 17.1 18.1 19.1 21.1 21.2 22.1 23.1 24.1 25.1 26.1 27.1 28.1 29.1 30.1 31.1 32.1 33.1 33.2 33.3
Днес се сблъсках с този проблем и искам да споделя решението, което открих в блога на Харалд. Една заявка изведнъж започна да се държи странно. Вместо да минава за нула време, отнема повече от час. Интересното е, че никой не я е променял от месеци. Очевидното в плана беше, че се прави FTS (Full Table Scan, да не се бърка с Formula Telecom Solutins ) на една от най-тлъстите ни таблици. И това се виждаше само в v$sql_plan – ако дам explain plan обещава, да мине през индекс. Използвах SELECT * FROM TABLE(dbms_xplan.display_awr(‘&sql_id’)); и видях, че плана е сгъбен от днес. Старите планове си минаваха през индекс. Защо се е променил (и то към лошо) – така и не се разбра. Не задълбах много в тази насока. Въпроса беше как мога да я изгоня от library cache, за да се генерира нов план. Най-драстичното решение е alter system flush shared_pool. Но това е като да си запалиш къщата, за да изгониш една мишка от нея. Да, този план вероятно ще се оправи, друг може пък да се счупи, а това ще е придружено от маса CPU докато се напарснат всички заявки. Не, благодаря. Друго нещо, което ми хрумна, е да инвалидирам заявката като пусна някакъв празен DDL на някоя от таблиците. Варианти много – примерно да сложа коментар (и това е DDL). Алтернативно мога да set-на статистики на някоя колона (без да ги променям). Тук лошото е отново големия размах, с който се действа – инвалидира се всичко, свързано с тази таблица. Решението, което предлага Харалд, е много елегантно. Пакета dbms_shared_pool има процедура purge, която прави точно това – изритва нещо (било то курсор, пакет, или друго) от library cache. По принцип тя е нова в 11.1, но е толкова ценна, че са я добавили в 10.2.0.4. Има, обаче, две подробности. Първо, в нашата версия на dbms_shared_pool нямаше тази процедура. Това се оправя лесно: @?/rdbms/admin/dbmspool След това тествах, тествах – то не бачка. Процедурата си минава, но не прави нищо полезно. Тогава се зачетох из коментарите на блога на Харалд и намерих това: alter session set events '5614566 trace name context forever'; След това нещата потръгнаха: select address, hash_value from v$sqlarea where sql_id = '1mqxxf66dtgdp'; Тук параметъра C идва да покаже, че гоним курсор. По същия начин може да се изритат и други неща: – Value Kind of Object to keep – –– –––––––- – P package/procedure/function – Q sequence – R trigger – T type – JS java source – JC java class – JR java resource – JD java shared data – C cursor Ta… това е. Мисля, че е полезно. И работи, тествано е.
2.1 3.1 3.2 3.3 4.1 4.2 5.1 6.1 7.1 8.1 8.2 8.3 8.4 8.5 9.1 10.1 10.2 10.3 10.4 11.1 11.2 11.3 11.4 12.1 12.2 13.1 14.1 14.2 14.3 15.1 16.1 16.2 17.1 18.1 18.2 18.3 19.1 20.1 21.1 23.1 23.2 24.1 25.1 26.1 27.1 28.1 29.1 30.1 31.1 32.1 33.1 34.1 35.1 35.2
I needed this today and I want to share the solution i found in Harald’s blog. One single query started to work slow. It takes more than an hour, instead of a few seconds. An, of course, nobody touched this piece of code for months. It was easy to see that the plan makes FTS of one of the biggest tables in the database. And I could see this only in v$sql_plan – if I try explain plan it promises to use an index. I used SELECT * FROM TABLE(dbms_xplan.display_awr('&sql_id')); and I saw the plan gone wrong today. The old executions were using the index access. What caused this change (a bad one) – nobody knows. I did not invest much time on this. The question is how to remove the query out of the library cache, so that it could generate a new (old) indexed plan. The most dramatic approach is alter system flush shared_pool. It’s like putting your house on fire to kill that mises inside. Yes, this plan will possibly get better, another one may get worse, and that will be combined with a lot of CPU usage until all statements get parsed again. No, thanks. Another idea is to invalidate the cursor by running some DDL on one of the tables referenced by the query. We have plenty of options for this – like putting a comment (yes, this is a DDL). An alternative approach is to set column statistics for some column (w/o actually changing the values). But again, this is too “general”- all statements on this table will be invalidated. Harald’s solution is much more elegant. The package dbms_shared_pool has a procedure purge, which makes what I need – removes “something” (like a cursor or a package) from the library cache. This is new in 11.1, but it is so useful, that Oracle decided to backport it to 10.2.0.4. But there are some details. First, our dbms_shared_pool did not provide this procedure (although the database is 10.2.0.4.1). This can be fixed using: @?/rdbms/admin/dbmspool Then I tested it again and again – it did not work at all. The procedure executes just fine, but does not make any change. Then I started reading the comments in Harald’s blog and I found this: alter session set events '5614566 trace name context forever'; This fixed the procedure: select address, hash_value from v$sqlarea where sql_id = '1mqxxf66dtgdp'; The value of the third parameter (C) stands for “Cursor”. The other options are: — Value Kind of Object to keep — —– ———————- — P package/procedure/function — Q sequence — R trigger — T type — JS java source — JC java class — JR java resource — JD java shared data — C cursor This is it. It works, and it is useful.