How do I fix an oracle Table/Index row count mismatch - oracle

I just had an oracle9 database crash and it left me with a couple of .trc files. Some of them specified indexes that were out of kilter and i dropped and readded those indexes.
However, when I run:
ANALYZE TABLE TABLESPACE.TABLE VALIDATE STRUCTURE CASCADE;
I still get an error: ora_00900, sqlstate: 4200
This creates a .trc file with:
Table/Index row count mismatch
table 1172 : index 1250, 0
Index root = tsn: 9 rdba: 0x0240390b
What do I do with this information?
I found this link, however I'm not sure how to use it:
http://www.freelists.org/post/oracle-l/Table-index-mismatch-trace-file,1

The error says your indexes (perhaps not the ones you thought) are still bad.
From your link, if you run the query through SQL*PLUS it will ask for a rdba number. Enter the value from your error message '0x0240390b' (no quotes). This will return a file number and a block number.
SELECT dbms_utility.data_block_address_file(
to_number(trim(leading '0' from
replace('&&rdba','0x','')),'XXXXXXXX')
) AS rfile#,
dbms_utility.data_block_address_block(
to_number(trim(leading '0' from
replace('&&rdba','0x','')),'XXXXXXXX')
) AS block#
FROM dual;
Next run the following query:
select owner, segment_name, segment_type
from dba_segments
where header_file = <rfile#>
and header_block = <block#>
This will give you the offending index to be dropped and recreated.

To be honest, with an error like this I would recommend opening an SR with Oracle - you want to make sure you don't lose your data!

Related

Unable to extend temp segment by 16 in tablespace PSTEMP

The query that gives me this error was running for 6 months now and it was working fine. Today for some reason gave me this error:
Error in running query because of SQL Error, Code=1652, Message=ORA-01652: unable to extend temp segment by 16 in tablespace PSTEMP (50,380).
I don't want to extend "PSTEMP" file. The query shouldn't be the problem as I mentioned it worked fine until now.
I don't know if that will help but the query has prompt value and if I enter a wrong value it works fine but when I enter the value from last week I know it should return 16 rows but instead I get the above error.
You can check your temp space with
SELECT * FROM dba_temp_free_space;
but it might not necessarily be temp despite the error message.
Check your tablespace free space with:
select a.tablespace_name,sum(a.tots/1048576) Tot_Size,
sum(a.sumb/1048576) Tot_Free,
round(sum(a.sumb)*100/sum(a.tots),2) Pct_Free,
sum(a.largest/1024) Max_Free,sum(a.chunks) Chunks_Free
from
(
select tablespace_name,0 tots,sum(bytes) sumb,
max(bytes) largest,count(*) chunks
from dba_free_space a
group by tablespace_name
union
select tablespace_name,sum(bytes) tots,0,0,0 from
dba_data_files
group by tablespace_name) a
group by a.tablespace_name
order by pct_free;
Most likely, your SQL became too heavy as the underlying data grew. You can try optimizing the SQL or if that's not an option, ask the DBAs to increase the undo tablespace (PSTEMP).

Using CFQUERY and Returning a Recordset Using an Oracle Anonymous Block

Reference: Oracle SQL RETURN INTO Fails within CFQUERY (ORA-06550/PLS-00103)
Placing the PL/SQL into a variable then executing in a CFQUERY tag works, but when I dump the query variable, I get "Variable XX is undefined".
How do I get the anonymous block to return the id of the affected record, or better yet, the entire record?
Below is the code which executes, but throws the error...
<cfset plsql = "
DECLARE record_id scpricequeue.scpricequeueid%TYPE;
BEGIN
update scpricequeue
set datelocked = sysdate
where scpricequeueid = (
select scpricequeueid
from (
select scpricequeueid
from scpricequeue
where islocked = 0 and completed = 0
order by dateadded asc
)
where rownum <= 1
)
RETURNING scpricequeueid INTO record_id;
END;
">
<cfset sql = "
select *
from scpricequeue
">
<cfquery name="q" datasource="ecomd">
#plsql#
</cfquery>
<cfdump var="#q#">
ERROR: Variable q is undefined
I solved my specific need in another way, by using SELECT ... FOR UPDATE
When you issue a SELECT statement against the database to query some records, no locks are placed on the selected rows. In general, this is a wonderful feature because the number of records locked at any given time is kept to the absolute minimum: only those records that have been changed but not yet committed are locked. Even then, others are able to read those records as they appeared before the change (the “before image” of the data).
There are times, however, when you will want to lock a set of records even before you change them in your program. Oracle offers the FOR UPDATE clause of the SELECT statement to perform this locking.
When you issue a SELECT...FOR UPDATE statement, the database automatically obtains row-level locks on all the rows identified by the SELECT statement, holding the records “for your changes only” as you move through the rows retrieved by the cursor. It’s as if you’ve issued an UPDATE statement against the rows, but you haven’t—you’ve merely SELECTed them. No one else will be able to change any of these records until you perform a ROLLBACK or a COMMIT—but other sessions can still read the data.
Ref: Oracle PL-SQL by O’Reilly, Pg 492
However, I was also tracking down a couple other more complex but promising solutions. I never reached conclusion, but in the hopes that these are useful pointers for others, here they are.
Oracle Package/CF Stored Procedure: See section titled “Use Oracle referenced cursors to return result sets (ColdFusion 4.5+, Oracle 7.3+):” and “Oracle PL-SQL” (Chapter 18 on Packages). I just hadn't figured out how to create the package and link it to CF, but this seemed like it would definitely be a viable solution.
I was going to test to see if CFTRANSACTION puts a lock on a record, which would be similar to my SELECT...FOR UPDATE solution above.

Recovering deleted Records

I have accdently deleted some rows in a table and did the commit too. Now
I want to recover them.
The DB I'm using is Oracle 11g R2.
I used the following query to get deleted records:
SELECT * FROM MY_TABLE AS OF TIMESTAMP ('13-MAR-11 8:50:58','DD-MON-YY HH24: MI: SS')
But while executing it gives an error saying:
Error at Command Line:3 Column:75
Error report:
SQL Error: ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
But I couldn't figure the problem in this queury.
Can anyone pls help?
That requires an actual timestamp (or date), you're passing a pair of values.
Try:
SELECT * FROM MY_TABLE
AS OF TIMESTAMP TO_DATE('13-MAR-11 08:50:58','DD-MON-YY HH24:MI:SS')
(Your time format specifier isn't correct either and doesn't match your date string.)
for example :
SELECT * FROM EMP AS OF TIMESTAMP
TO_TIMESTAMP('2005-04-04 09:30:00', 'YYYY-MM-DD HH:MI:SS')
WHERE name = 'JOHN';
But flashback query may fail with ORA-1555 , other option :
Logminer
if Oracle supplement log is enabled , you can get undo sql for your delete statement
-- switch again logfile to get a minimal redo activity alter system switch logfile;
-- mine the last written archived log
exec dbms_logmnr.add_logfile('archivelog/redologfile', options =>dbms_logmnr.new);
exec dbms_logmnr.start_logmnr(options => dbms_logmnr.dict_from_online_catalog);
select operation, sql_redo from v$logmnr_contents where seg_name = 'EMP';
Oracle PRM-DUL
PRM-DUL will be last option. Even deleted row piece in Oracle block is always just marked row flag with deleted mask, the row piece still can be read via scan Oracle data block . PRM-DUL can scan the whole table , find out every record/row piece marked deleted and write out to flat file.

ORA-01747: invalid user.table.column, table.column, or column specification

Get the above error when the execute immediate is called in a loop
Update CustomersPriceGroups set 1AO00=:disc Where cuno=:cuno
Parameters: disc=66 cuno=000974
Update CustomersPriceGroups set 1AP00=:disc Where cuno=:cuno
Parameters: disc=70.5 cuno=000974
Update CustomersPriceGroups set 1AQ00=:disc Where cuno=:cuno
Parameters: disc=66 cuno=000974
Update CustomersPriceGroups set 1ZA00=:disc Where cuno=:cuno
Parameters: disc=60 cuno=000974
What does this mean ?
Here is the code fragment
c:=PriceWorx.frcPriceListCustomers('020','221');
LOOP
fetch c into comno,cuno,nama,cpls;
exit when c%notfound;
dbms_output.put_Line(cuno);
g:=priceWorx.frcPriceListItemGroups('020','221');
d:=priceworx.frcCustomerDiscounts('020','221',cuno);
loop
fetch g into comno,cpgs,n;
fetch d into comno,cpls,cuno,cpgs,stdt,tdat,qanp,disc,src;
--dbms_output.put(chr(9)||cpgs);
sQ:='Update saap.CustomersPriceGroups set "'|| trim(cpgs)||'"=:disc '
|| ' Where cuno=:cuno';
execute immediate sQ using disc,cuno;
commit;
dbms_output.put_line( sQ );
dbms_output.put_line( chr(9)||'Parameters: disc='|| disc||' cuno='||cuno);
exit when g%notfound;
end loop;
close g;
close d;
end loop;
check your query for double comma.
insert into TABLE_NAME (COLUMN1, COLUMN2,,COLUMN3) values(1,2,3);
(there is extra comma after COLUMN2).
Update: recently (some people have special talents) i succeed to get same exception with new approach:
update TABLE_NAME set COLUMN1=7, set COLUMN2=8
(second SET is redundant)
Unquoted identifiers must begin with an alphabetic character (see rule 6 here). You're trying to assign a value to a column with a name starting with a number 1AO00, 1AP00 etc.
Without seeing the table definition for CustomersPriceGroups we don't know if it has columns with those names. If it does then they must have been created as quoted identifiers. If so you'll have to refer to them (everywhere) with quotes, which is not ideal - makes the code a bit harder to read, makes it easy to make a mistake like this, and can be hard to spot what's wrong. Even Oracle say, on the same page:
Note: Oracle does not recommend using quoted identifiers for database
object names. These quoted identifiers are accepted by SQL*Plus, but
they may not be valid when using other tools that manage database
objects.
In you code you appear to be using quotes when you assign sQ, but the output you show doesn't; but it doesn't have the saap. schema identifier either. That may be because you're not running the version of the code you think, but might just have been
lost if you retyped the data instead of pasting it - you're not showing the earlier output of c.cuno either. But it's also possible you have, say, the case of the column name wrong.
If the execute is throwing the error, you won't see the command being executed that time around the loop because the debug comes after it - you're seeing the successful values, not the one that's breaking. You need to check all the values being returned by the functions; I suspect that g is returning a value for cpgs that actually isn't a valid column name.
As #ninesided says, showing more information, particularly the full exception message, will help identify what's wrong.
It means that the Oracle parser thinks that one of your columns is not valid. This might be because you've incorrectly referenced a column, the column name is reserved word, or because you have a syntax error in the UPDATE statement that makes Oracle think that something which is not a column, is a column. It would really help to see the full statement that is being executed, the definition of the CustomersPriceGroups table and the full text of the exception being raised, as it will often tell which column is at fault.
if you add a extra "," at the end of the set statement instead of a syntax error, you will get ORA-01747, which is very very odd from Oracle
e.g
update table1
set col1 = 'Y', --this odd 1
where col2 = 123
and col3 = 456
In addition to reasons cited in other answers here, you may also need to check that none of your table column names have a name which is considered a special/reserved word in oracle database.
In my case I had a table column name uid. uid is a reserved word in oracle and therefore I was getting this error.
Luckly, my table was a new table and I had no data in it. I was a able to use oracle DROP table command to delete the table and create a new one with a modified name for the problem column.
I also had trouble with renaming the problem column as oracle wouldn't let me and kept throwing errors.
You used oracle keyword in your SQL statement
And I was writing query like. I had to remove [ and ]
UPDATE SN.TableName
SET [EXPIRY_DATE] = systimestamp + INTERVAL '12' HOUR,
WHERE [USER_ID] ='12345'
We recently moved from SQL Server to Oracle.
The cause may also be when you group by a different set of columns than in select for example:
select tab.a, tab.b, count(*)
from ...
where...
group by tab.a, tab.c;
ORA-01747: invalid user.table.column, table.column, or column
specification
You will get when you miss the column relation when you compare both column id your is will not be the same check both id in your database
Here is the sample Example which I was facing:
UPDATE TABLE_NAME SET APPROVED_BY='1000',CHECK_CONDITION=ID, WHERE CONSUMER_ID='200'
here Issue you will get when 'CHECK_CONDITION' and 'ID' both column id will no same
If both id will same this time your query will execute fine, Check id Id both Column you compare in your code.
For me, the issue was due to use to column name "CLUSTER" which is a reserved word in Oracle. I was trying to insert into the column. Renaming the column fixed my issue.
insert into table (JOB_NAME, VERSION, CLUSTER, REPO, CREATE_TS) VALUES ('abc', 169, 'abc.war', '1.3', 'test.com', 'test', '26-Aug-19 04.27.09.000000949 PM')
Error at Command Line : 1 Column : 83
Error report -
SQL Error: ORA-01747: invalid user.table.column, table.column, or column specification
In my case, I had some.* in count. like count(dr.*)

Oracle refuses to use index

I have a partitioned table like so:
create table demo (
ID NUMBER(22) not null,
TS TIMESTAMP not null,
KEY VARCHAR2(5) not null,
...lots more columns...
)
The partition is on the TS column (one partition per year).
Since I search a lot via the timestamp, I created a combined index:
create index demo.x1 on demo (ts, key);
The query looks like this:
select *
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
I also tried to add and t.KEY = '00101' but that doesn't help.
But EXPLAIN PLAN says that TABLE ACCESS and FULL:
# Operation Options Object Mode Cost Bytes Cardinality
0 SELECT STATEMENT ALL_ROWS 583804 287145 2127
1 PARTITION RANGE ALL 583804 287145 2127
2 TABLE ACCESS FULL HEADER ANALYZED 583804 287145 2127
No mention of the index. What could be wrong?
[EDIT] For some reason, Oracle completely miscalculated the cost for the operation. I have 112 million rows in that table. The cost for a full scan of a single partition should be 20 million, not 600'000. That's why it even ignores optimizer hints.
[EDIT2] During my tests, I ran over this puzzling result. When I run this select:
select tx_ts
from kt.header
where tx_ts = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
I get this EXPLAIN PLAN:
0 SELECT STATEMENT ALL_ROWS 152 15616 1952
1 PARTITION RANGE ALL 152 15616 1952
2 INDEX FAST FULL SCAN HEADERX2 ANALYZED 152 15616 1952
So when I restrict myself to the indexed column as the result of the select, Oracle decides to use the index. When I want to get all columns, I have to wait for a full table scan. What's going on here?
[EDIT2] Found it; see my answer below.
Okay, it was a mistake on my part: The column had the type DATE, not TIMESTAMP. Since I used to_timestamp(), Oracle saw no way to use the index.
I'm not really an expert on partitioning, but I think what has happened here is that you have created a global index -- a single index that covers rows in all of the partitions. Therefore, the optimizer has to choose between two mutually exclusive access paths: (A) an index range scan, or (B) partition pruning. I believe the PARTITION RANGE operation indicates that it has chosen B.
Updating statistics, as others have suggested, may change the behavior. When you drop and recreate the index, you discard any statistics that existed for the index.
Creating the index as UNIQUE, if the timestamp and key uniquely identify a row, would be a good idea and might change the behavior as well.
However, I think the real "fix" is that you should instead create local indexes -- a separate index on each partition. This should enable the optimizer to do partition pruning followed by an index lookup. Honestly, I'm not sure what the exact syntax is to do this. Maybe you just create the index on each partition explicitly using the individual partition names.
If everything else fails, you might try an optimizer hint:
select /*+ index(demo.demo demo.x1) */ *
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS')
Are your stats up to date? Invalid stats may mean that oracle believes a full table scan is faster than using the index. Are you using any hints in your query that might be telling oracle to do a full scan?
Can you supply us with the full query and explain plan results?
Edit: Aaron, you can update the stats using "dbms_stats.gather_schema_stats" or "dbms_stats.gather_table_stats" commands. See here for more information on the commands. This will update all the relevant stats for the schema or table specified. Oracle's Cost Based Optimiser will use the statistics to determine which execution plan to choose. It never uses the actual table sizes. You'll need to re-update your stats when the size of your table changes significantly ( +/- 10% or so)
Another thing. When you use a compound index, you need to specify all the columns used in the index in your query for the optimizer to consider the index (and I think you need to specify them in the same order as well, though I could be wrong about that, it's been a while since I looked at this stuff)
There may just be a typo in your transcription of the "CREATE INDEX..." statement that you posted, but are you sure you actually have created the index?
To give us some first-pass idea of the statistics, use these queries:
select table_name, num_rows
from user_tables
where table_name = 'DEMO';
select table_name, num_rows
from user_tab_partitions
where table_name = 'DEMO';
select index_name, num_rows from user_indexes
where table_name in
(select table_name
from user_tables where table_name = 'DEMO');
Also, exactly how are you generating the EXPLAIN PLAN? Do you have access to the database host to retrieve a trace file if you enable tracing?
[edit]
As I commented, it would be good to see the trace of an actual execution of the query. Since you've indicated you have access to the db host filesystems, run a SQL script that (in the same session) issues the following:
alter session set sql_trace=true;
select /* THIS IS THE TRACE */
*
from demo t
where t.TS = to_timestamp('2009-06-30 07:47:57', 'YYYY-MM-DD HH24:MI:SS');
exit
After the script exits, find out
where the trace file directory is by
this query:
select value from v$parameter where name = 'user_dump_dest';
Use whatever searching tool is
available to you to find the file
that includes the string "THIS IS THE
TRACE"
Process/profile the trace file by
issuing the OS command tkprof
traceFileName.trc tkprof.out
Examine this file - you'll see some overhead information, but there will be a section that details the actual execution plan and statistics for the query. If you see the same results in this information then the next step is to add another statement (after the first "alter session") that will dump information on why the Oracle CBO is ignoring the index:
ALTER SESSION SET EVENTS='10053 trace name context forever, level 1';

Resources