Oracle SQL: Single Index with two Columns vs index on one Column - oracle

I'm using Oracle12c
I have a table with a primary key and separate column.
create tableB(
ID number(10)
,data number(10)
);
ID is my primary key.
I have to join 3 tables on my query and the performance issue is the B.data without an index.
B.data contains 'null' values and multiple entries on the same numbers.
select A.examp from tabled D
join tableb B on D.data = B.data
join tablec C on B.ID = C.ID
join tablea A on C.val = A.val
where D.ID = :value;
So my question is what is the difference between an index that contains only one value like the data column
create index ind_tableb on tableb (data);
and an index that contains multiple columns like
create index ind_tableb on tableb (data, id);
Can i get an improvement by selecting the id in the index with the data in the way i join the columns ?
Thanks for any advise and help.

For this particular query, you want the two column index version:
create index ind_tableb on tableb (data, id);
The above index, if used, would let Oracle rapidly lookup tabled.data values for a potential match with a tableb.data value. If a match be found, then the same index would also contain the tableb.ID value for the next join to tablec. If you just used the single column version on tableb.data alone, then Oracle would have to seek back to the tableb table to find the ID values. This could hurt performance and might even cause the index to not be used.

Related

Deleting data from one table using data from a second table

I have a table table1, where there is a million data and a completely identical table table2, only there are only 106 data. How it is possible to delete these 106 data from table1?
In these two tables i have fields like id, date, param0, param1, param2.
Presuming that uniqueness is enforced through the ID column in both tables, then:
delete from table1 a
where exists (select null
from table2 b
where b.id = a.id
);
Otherwise, add some more columns (into the where clause) which will help you delete only rows you really want.

Data Migration - Verify Data loaded where Primary Key can change

I am currently trying to write SQL to verify the counts of the data that has been migrated from one application to another.
One of the main tables that is being migrated sometimes contains a primary key that already exists in the target application so it needs to be changed. This results in my counts not matching up.
I have a reference table for these changed primary keys but I'm not sure how to incorporate this reference table into my left join.
I really don't know how to include the condition where the key from Table A could be the key on Table B or the new key stored on the Reference table?
select count(*)
from table_b b
left join table_a a on
b.key = a.key
where a.key is null;
The reference table is really simple, two colmumns, old_number, new_number. It will only contain entries where the key in table A needed to be changed before being loaded into table B.
old_number, new_number
12345678, 13345678
23456781, 24456781
How can I include this scenario?
select count(*)
from table_b b
left join table_a a on
b.key = (a.key or new_number if it exists)
where a.key is null;
So, if the query can include the new_numbers in the reference table then the migration count should match the count in Table A.
This should work
select count() from table_b b, table_a a where b.key = a.key UNION select count() from table_b b, reference_table re where b.key = re.new_number;

Using "contains" as a way to join tables?

The Primary key in table one is used as in table 2 but it is modified as so:
Primary key Column in table 1: 123abc
Column in table 2: 123abc_1
I.e. the key is used but then _1 is added to create a unique value in the column of Table 2.
Is there any way that I can join the two tables, the data in the 2 columns is not identical but it very similar. Could I do something like:
SELECT *
FROM TABLE1 INNER JOIN
TABLE2
ON TABLE1.COUMN1 contains TABLE2.COLUMN2;
I.e. checking that the value in Table 1 is within the value in Table 2?
You can check only the first part of column2; for example
SELECT *
FROM TABLE1 INNER JOIN TABLE2
ON INSTR(COLUMN2, COLUMN1) = 1
or
ON COLUMN2 LIKE COLUMN1 || '%'
However, keeping foreign key in such a way can be really dangerous, not to think about performance on large DBs.
You'd better use a different column in Table2 to store the key of Table 1, even adding a constraint.

optimize query with minus oracle

Wanted to optimize a query with the minus that it takes too much time ... if they can give thanked help.
I have two tables A and B,
Table A: ID, value
Table B: ID
I want all of Table A records that are not in Table B. Showing the value.
For it was something like:
Select ID, value
FROM A
WHERE value> 70
MINUS
Select ID
FROM B;
Only this query is taking too long ... any tips how best this simple query?
Thank you for attention
Are ID and Value indexed?
The performance of Minus and Not Exists depend:
It really depends on a bunch of factors.
A MINUS will do a full table scan on both tables unless there is some
criteria in the where clause of both queries that allows an index
range scan. A MINUS also requires that both queries have the same
number of columns, and that each column has the same data type as the
corresponding column in the other query (or one convertible to the
same type). A MINUS will return all rows from the first query where
there is not an exact match column for column with the second query. A
MINUS also requires an implicit sort of both queries
NOT EXISTS will read the sub-query once for each row in the outer
query. If the correlation field (you are running a correlated
sub-query?) is an indexed field, then only an index scan is done.
The choice of which construct to use depends on the type of data you
want to return, and also the relative sizes of the two tables/queries.
If the outer table is small relative to the inner one, and the inner
table is indexed (preferrable a unique index but not required) on the
correlation field, then NOT EXISTS will probably be faster since the
index lookup will be pretty fast, and only executed a relatively few
times. If both tables a roughly the same size, then MINUS might be
faster, particularly if you can live with only seeing fields that you
are comparing on.
Minus operator versus 'not exists' for faster SQL query - Oracle Community Forums
You could use NOT EXISTS like so:
SELECT a.ID, a.Value
From a
where a.value > 70
and not exists(
Select b.ID
From B
Where b.ID = a.ID)
EDIT: I've produced some dummy data and two datasets for testing to prove the performance increases of indexing. Note: I did this in MySQL since I don't have Oracle on my Macbook.
Table A has 2600 records with 2 columns: ID, val.
ID is an autoincrement integer
Val varchar(255)
Table b has one column, but more records than Table A. Autoincrement (in gaps of 3)
You can reproduce this if you wish: Pastebin - SQL Dummy Data
Here is the query I will be using:
select a.id, a.val from tablea a
where length(a.val) > 3
and not exists(
select b.id from tableb b where b.id = a.id
);
Without Indexes, the runtime is 986ms with 1685 rows.
Now we add the indexes:
ALTER TABLE `tablea` ADD INDEX `id` (`id`);
ALTER TABLE `tableb` ADD INDEX `id` (`id`);
With Indexes, the runtime is 14ms with 1685 rows. That's 1.42% the time it took without indexes!

Oracle query to get the results of a particular table using the result obtained from another table

I am new to Oracle, so kindly bear with me if the question sounds really naive.
So, I have two tables TableA and TableB which have say just two columns id, name for simplicity.
I now want to now get the id value for a particular value of name in TableA. If this would be the only requirement, this query would suffice -
SELECT id from TableA WHERE name = 'some_name';
Now, what I want to do is take this id and delete all the rows in TableB that match this id-
DELETE FROM TableB WHERE id = <id obtained from the above query>;
What is the composite query in oracle that would perform this function?
Thanks!
If you know that only a single id value is going to be returned for a particular name value, you'd just do
DELETE FROM tableB b
WHERE b.id = (SELECT a.id
FROM tableA a
WHERE a.name = 'some_name')
Note that the aliases are optional. However, adding aliases generally makes things clearer so no one has to guess which id or which name you're referring to at any point.
If there might be multiple id values in tableA for a given name, you'd just use an IN rather than an =
DELETE FROM tableB b
WHERE b.id IN (SELECT a.id
FROM tableA a
WHERE a.name = 'some_name')
This would also work if you knew that the query against tableA was only going to return one row. I'd prefer the equality query if you're sure that only one row would be returned, though. I'd generally rather get an error if my expectations were violated rather than potentially having unexpected rows get deleted.

Resources