Hello I am not very experienced on Oracle DB administration, I have several queries that started to work really slow and all involve with temp table (12c). I see several posts talking about disable stats on GTT (Global Temporary Table), however I didn't find much but just following setting to disable
exec dbms_scheduler.disable('SYS.GATHER_STATS_JOB');
my question is any specific way to turn off stats ONLY to GTT, and what is the negative impact on above command?
This disables statistics gathering on a table
begin
dbms_stats.delete_table_stats('TABLE_OWNER', 'TABLE_NAME');
dbms_stats.lock_table_stats('TABLE_OWNER', 'TABLE_NAME');
end;
/
However a better idea is to collect statistics on the table when it is filled with representative data set:
begin
dbms_stats.gather_table_stats('TABLE_OWNER', 'TABLE_NAME');
dbms_stats.lock_table_stats('TABLE_OWNER', 'TABLE_NAME');
end;
/
https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_stats.htm#i1043993
Related
I have several Oracle databases where my in-house applications are running. Those applications use both dba_jobs and dba_scheduler_jobs.
I want to write monitoring function: check_my_jobs which will be called periodically by Nagios to check if everything is OK with my jobs. (Are they running? Is it Broken? Is next_run_date delayed? and so on)
Solutions: Due to the fact that I have to monitor jobs on different databases there is two way of implementing solution:
Create a monitoring function and configuration tables only on one database which will check jobs on every database using database links.
pros: Centralized functionality, easy to maintain.
cons: I have to do the checks using database links.
Create a monitoring function and configuration tables on every database where I want to check jobs.
pros: I don't have to use DB links
cons: Duplicated monitoring code on every database
Which solution is better?
I'd go with option #1 - centralized functionality that uses database links.
Database links have an undeserved bad reputation. One of the main reasons is that too many people use public database links, where anyone connecting to the database can use the link. That's obviously a security nightmare, but it's not the default setting and it's easy to avoid that trap.
Some other issues with database links:
They don't perform well for huge inserts of millions of rows. On the other hand they're great at many small SELECTs or INSERTs. I frequently have hundreds of links open and fetching data concurrently, on 10 year-old hardware, and it works great.
They make execution plans more difficult to troubleshoot.
Not all data types are natively supported. This is better in 12.2, but in earlier versions you will need to use an INSERT to move data types like CLOB into tables, and then read from those tables.
For DDL you'll need to use DBMS_UTILITY.EXEC_DDL_STATEMENT#LINK_NAME('create ...'); Make sure to only use DDL in there. Other types of commands will silently fail.
Links may hang indefinitely in a few rare situations, like if the database has an archiver error or a guaranteed restore point that's full. (This one is really a blessing in disguise - many tools like Oracle Enterprise Manager will not catch those issues. You may want to have a background job checking for database link queries that have been running longer than X minutes.)
Links should not be hard-coded or else they could invalidate the package. But this may not matter - you'll probably want to loop through the list of databases and use dynamic SQL anyway. And if the link doesn't exist it's pretty easy to create a new one. Here's an example:
declare
v_result varchar2(4000);
begin
--Loop through a configuration table of links.
for links in
(
select database_name, db_link
from dbs_to_monitor
left join user_db_links
on dbs_to_monitor.database_name = user_db_links.db_link
order by database_name
) loop
--Run the query if the link exists.
if links.db_link is not null then
begin
--Note the user of REPLACE and the alternative quoting mechanism, q'[...]';
--This looks a bit silly with this small example, but in a real-life query
--it avoids concatenation hell and makes the query much easier to read.
execute immediate replace(q'[
select dummy from dual##DB_LINK#
]',
'#DB_LINK#', links.db_link)
into v_result;
dbms_output.put_line('Result: '||v_result);
--Catch errors if the links are broken or some other error happens.
exception when others then
dbms_output.put_line('Error with '||links.db_link||': '||sqlerrm);
end;
--Error if the link was not created.
--You will have to run:
--create database link LINK_NAME connect to USERNAME identified by "PASSWORD" using 'TNS_STRING';
else
dbms_output.put_line('ERROR - '||links.db_link||' does not exist!');
end if;
end loop;
end;
/
Despite all of that, database links are great because you can do everything in PL/SQL, on one database. In a single language you can create an agentless monitoring solution and don't have to worry about installing and fixing agents.
As an example, I built the open source program Method5 to do everything using database links. With that program installed you could gather results from hundreds of databases as simply as running select * from table(m5('select * from dba_jobs'));. That program is probably overkill for your scenario but it shows that database links are all you need for a full monitoring solution.
We have one of our system that perform quite a bit of database activity in terms of INSERT/UPDATE/DELETE statements against various tables. Because of this the statistics became stale and this is reflected in overall performance.
We want to create a scheduled job that would periodically invoke DBMS_STATS.GATHER_SCHEMA_STATS. Because we don't want actual stats gathering itself to impact the system processing even more we are thinking to collect statistics quite frequent and use GATHER STALE option:
DBMS_STATS.GATHER_SCHEMA_STATS(OWNNAME => 'MY_SCHEMA', OPTIONS =>'GATHER STALE')
This executes almost instantly but running this statement below before and after stats gathering seems to bring back the same records with the same values:
SELECT * FROM user_tab_modifications WHERE inserts + updates + deletes > 0;
The very short time taking to execute and the fact that user_tab_modifications content stays the same makes me question if OPTIONS =>'GATHER STALE' actually does what we expect it should do. On the other hand if I run this again before and after statistics gathering I can see the tables reported as stale before re no longer reported as stale after:
DECLARE
stale dbms_stats.objecttab;
BEGIN
DBMS_STATS.GATHER_SCHEMA_STATS(ownname => 'MY_SCHEMA', OPTIONS =>'LIST STALE', objlist => stale);
FOR i in 1 .. stale.count
LOOP
dbms_output.put_line( stale(i).objName );
END LOOP;
END;
On another hand if lets say my_table is one of my tables being listed as part of the tables that part of the user_tab_modifications with inserts + updates + deletes > 0 and I run I can see my_table no longer being reported as having changes.
EXECUTE DBMS_STATS.GATHER_TABLE_STATS(ownname => 'MY_SCHEMA', tabname => 'MY_TABLE');
So my questions are:
Is my approach correct. Can I trust I am getting fresh stats just by running options => 'GATHER STALE' or I should manually collect stats for all tables that come back with a reasonable number of inserts, updates, deletes?
When user_tab_modifications would actually get reset; obviously GATHER STALE option does not seem to do it
We are using Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
Got the following info from Oracle docs.
You should enable monitoring if you use GATHER_DATABASE_STATS or GATHER_SCHEMA_STATS with the GATHER AUTO or GATHER STALE options.
This view USER_TAB_MODIFICATIONS is populated only for tables with the MONITORING attribute. It is intended for statistics collection over a long period of time. For performance reasons, the Oracle Database does not populate this view immediately when the actual modifications occur. Run the FLUSH_DATABASE_MONITORING_INFO procedure in the DBMS_STATS PL/SQL package to populate this view with the latest information. The ANALYZE_ANY system privilege is required to run this procedure.
Hope this helps you to identify which of your assumptions are incorrect and understand the correct usage of "GATHER STALE".
Questions have been asked in the past that seems to handle pieces of my full question, but I'm not finding a totally good answer.
Here is the situation:
I'm importing data from an old, but operational and production, Oracle server.
One of the columns is created as LONG RAW.
I will not be able to convert the table to a BLOB.
I would like to use a global temporary table to pull out data each time I call to the server.
This feels like a good answer, from here: How to create a temporary table in Oracle
CREATE GLOBAL TEMPORARY TABLE newtable
ON COMMIT PRESERVE ROWS
AS SELECT
MYID, TO_LOB("LONGRAWDATA") "BLOBDATA"
FROM oldtable WHERE .....;
I do not want the table hanging around, and I'd only do a chunk of rows at a time, to pull out the old table in pieces, each time killing the table. Is it acceptable behavior to do the CREATE, then do the SELECT, then DROP?
Thanks..
--- EDIT ---
Just as a follow up, I decided to take an even different approach to this.
Branching the strong-oracle package, I was able to do what I originally hoped to do, which was to pull the data directly from the table without doing a conversion.
Here is the issue I've posted. If I am allowed to publish my code to a branch, I'll post a follow up here for completeness.
Oracle ODBC Driver Release 11.2.0.1.0 says that Prefetch for LONG RAW data types is supported, which is true.
One caveat is that LONG RAW can technically be up to 2GB in size. I had to set a hard max size of 10MB in the code, which is adequate for my use, so far at least. This probably could be a variable sent in to the connection.
This fix is a bit off original topic now however, but it might be useful to someone else.
With Oracle GTTs, it is not be necessary to drop and create each time, and you don't need to worry about data "hanging around." In fact, it's inadvisable to drop and re-create. The structure itself persists, but the data in it does not. The data only persists within each session. You can test this by opening up two separate clients, loading data with one, and you will notice it's not there in the second client.
In effect, each time you open a session, it's like you are reading a completely different table, which was just truncated.
If you want to empty the table within your stored procedure, you can always truncate it. Within a stored proc, you will need to execute immediate if you do this.
This is really handy, but it also can make debugging a bear if you are implementing GTTs through code.
Out of curiosity, why a chunk at a time and not the entire dataset? What kind of data volumes are you talking about?
-- EDIT --
Per our comments conversation, this is very raw and untested, but I hope it will give you an idea what I mean:
CREATE OR REPLACE PROCEDURE LOAD_DATA()
AS
TOTAL_ROWS number;
TABLE_ROWS number := 1;
ROWS_AT_A_TIME number := 100;
BEGIN
select count (*)
into TOTAL_ROWS
from oldtable;
WHILE TABLE_ROWS <= TOTAL_ROWS
LOOP
execute immediate 'truncate table MY_TEMP_TABLE';
insert into MY_TEMP_TABLE
SELECT
MYID, TO_LOB(LONGRAWDATA) as BLOBDATA
FROM oldtable
WHERE ROWNUM between TABLE_ROWS and TABLE_ROWS + ROWS_AT_A_TIME;
insert into MY_REMOTE_TABLE#MY_REMOTE_SERVER
select * from MY_TEMP_TABLE;
commit;
TABLE_ROWS := TABLE_ROWS + ROWS_AT_A_TIME;
END LOOP;
commit;
end LOAD_DATA;
Im pretty new to oracle databases. The situation I have right now is that I need to extract and compare read/write performance statistics between File System and ASM in Oracle 11g Database Infrastructure R2.
I currently have two virtual machines, one is configured as File System and the other one is ASM (diskgroups are ok and good to go). Both running win7 pro x64 in separate physical HDDs on my computer.
The test that I came up with is to create a table in both DBs, and using a custom sequence I created, insert 100,000 records on them. Next thing, I will need to see how well did ASM performed compared to File System in terms of performance.
The problem? I dont know how to pull the performance statistics so that I can compare them. Can someone please help? It'll be much appreciated.
SQL> create sequence SQX
start with 1
increment by 1;
SQL> create table test(
x number(9),
y date);
SQL> begin
for i in 1.. 100000 loop
insert into test(x,y) values(SQX.nextval,sysdate);
end loop;
end;
/
You don't use the good method. The performance of the I/O system can be only evaluated with specific tools such as ORION (and some others).
This article from Tim Hall gives you a good overview of the possibilities you have: [http://oracle-base.com/articles/misc/measuring-storage-performance-for-oracle-systems.php].
Regards,
Cyryl
What are the means to schedule automatic "analyze tables". Is it possible to request an automatic "analyze tables" when a lot of data change througt insert and deletes? What are the means to parametrize the automatic analyze tables process, i.e. to set rules when it should be triggered.
What version of Oracle are you using? From 10.1 on, Oracle has shipped with an automatic job that gathers statistics every night on any object that has been changed substantially (based on an internal algorithm subject to change, but I believe the threshold is ~15%) since that last time statistics were gathered. Assuming you are using a currently supported release, statistics are gathered automatically by default unless you explicitly disable that job.
You can use the DBMS_STATS package to gather statistics on an object based on an event and you can use the DBMS_JOB (or DBMS_SCHEDULER) package to have that done asynchronously. So at the end of an ETL process, you can gather statistics
BEGIN
dbms_stats.gather_table_stats(
ownname => <<schema name>>,
tabname => <<table name>>
);
END;
You can have that run asynchronously
DECLARE
l_jobno INTEGER;
BEGIN
dbms_job.submit(
l_jobno,
'BEGIN dbms_stats.gather_table_stats( ''<<schema name>>'', ''<<table name>>'' ); END;',
sysdate + interval '1' minute
);
END;
"Is there a way to have this job being triggered when there is a substantial proportion of data changed"
In theory you could do an AFTER INSERT trigger on a table that automatically sets off DBMS_STATS.
But be careful what you wish for. If you are in the middle of a large ETL job, having just inserted a million rows into the table, you don't necessarily want to automatically immediately set off a DBMS_STATS job. Equally, when you are at your busiest on-line processing time (eg lunch) you don't want to slow it down by gathering stats at the same time.
You generally want these stats gathering jobs running at low-usage periods (nights, weekends). If you have a large batch run that loads into a lot of tables, I'd build the DBMS_STATS into the batch.