Database Indexing - oracle

I'm trying to figure out on how to create an Index for below query such that the SELECT statement only traverse the leaf level of the index horizontally and it does not access the relational table. I'm working on a relational database in Oracle.
SELECT SUM(SUM(qty))
FROM PlaceOrder
GROUP BY OrderNumber
HAVING COUNT(LineNumber) > 10;
Am I correct to create the below index?
CREATE INDEX IDX_PO
ON PlaceOrder(qty, OrderNumber, LineNumber);
Thank you.

As commented by astentx, not null constraint is needed. In fact, as long as any of qty, OrderNumber, LineNumber has not null, Oracle should be able to use the index.
Also, note that unless you specially want to exclude lines with null LineNumber, you can replace COUNT(LineNumber) with COUNT(OrderNumber) or even COUNT(*).

Related

find a best way to traverse oracle table

I have an oracle table. Table's DDL is (not have the primary key)
create table CLIENT_ACCOUNT
(
CLIENT_ID VARCHAR2(18) default ' ' not null,
ACCOUNT_ID VARCHAR2(18) default ' ' not null,
......
)
create unique index UK_ACCOUNT
on CLIENT_ACCOUNT (CLIENT_ID, ACCOUNT_ID)
Then, the data's scale is very huge, maybe 100M records. I want to traverse this whole table's data with batch.
Now, I use the table's index to batch traverse. But I have some oracle grammar problems.
# I want to use this SQL, but grammar error.
# try to use b-tree's index to locate start position, but not work
select * from CLIENT_ACCOUNT
WHERE (CLIENT_ID, ACCOUNT_ID) > (1,2)
AND ROWNUM < 1000
ORDER BY CLIENT_ID, ACCOUNT_ID
Has the fastest way to batch touch table data?
Wild guess:
select * from CLIENT_ACCOUNT
WHERE CLIENT_ID > '1'
and ACCOUNT_ID > '2'
AND ROWNUM < 1000;
It would at least compile, although whether it correctly implements your business logic is a different matter. Note that I have cast your filter criteria to strings. This is because your columns have a string datatype and you are defaulting them to spaces, so there's a high probability those columns contain non-numeric values.
If this doesn't solve your problem, please edit your question with more details; sample input data and expected output is always helpful in these situations.
Your data model seems odd.
Your columns are defined as varchar2. So why is your criteria numeric?
Also, why do you default the key columns to space? It would be better to leave unpopulated values as null. (To be clear, NULL is not a good thing in an indexed column, it's just better than a space.)

How to do the following query in Oracle NoSQL

I am planning to use NoSQL Cloud Service as our datastore. I have question about the MAP data type. Say I have a column “labels” ( labels MAP(RECORD(value STRING, contentType STRING)) in table “myTable”, which the “labels” column is MAP datatype and the value is RECORD data type .
I want to query the table which return all the rows that the key of the “labels” = particular value, what is the sql statement looks like? I tried:
select * from myTable where labels.keys($key=‘xxxx’)
which doesn’t work.
do we need to add the index for the label field in the MAP? any performance improvement? If yes, how to add this index?
Thanks
Please try the following syntax
select * from myTable t
where t.labels.keys() =any "xxx"
Your syntax is good if you add exists
select * from myTable t
where exists t.labels.keys($key= “xxx”)
Concerning your question about performance
there will be significant performance improvement.
If you want to index only the field names (keys) of the map,
you create the index like this:
create index idx_keys on myTable(labels.keys())
If you want to index both they keys and the associated values:
create index idx_keys_values
on myTable(labels.keys(), labels.values())

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: use index for searching null values

I've done some search but I prefer something like an hint or similar
http://www.dba-oracle.com/oracle_tips_null_idx.htm
http://www.oracloid.com/2006/05/using-index-for-is-null/
What about a functional index using NVL2, like;
CREATE TABLE foo (bar INTEGER);
INSERT INTO foo VALUES (1);
INSERT INTO foo VALUES (NULL);
CREATE INDEX baz ON foo (NVL2(bar,0,1));
and then;
DELETE plan_table;
EXPLAIN PLAN FOR SELECT * FROM foo WHERE NVL2(bar,0,1) = 1;
SELECT operation, object_name FROM plan_table;
should give you
OPERATION OBJECT_NAME
---------------- -----------
SELECT STATEMENT
TABLE ACCESS FOO
INDEX BAZ << yep
If you're asking, "How can I create an index that would allow it to be used when searching for NULL values on a particular field", my suggestion is to create an index on the field you're interested in PLUS the primary key field(s). Thus, if you've got a table called A_TABLE, with field VAL that you want to search for NULLs, and a primary key named PK, I'd create an index on (VAL, PK).
Share and enjoy.
I'm going to "answer" the non-question above.
The articles you link to are kinda right - Oracle's b-tree indexes will not capture when the leaf nodes are null. Take this example:
CREATE TABLE MYTABLE (
ID NUMBER(8) NOT NULL,
DAT VARCHAR2(100)
);
CREATE INDEX MYTABLE_IDX_1 ON MYTABLE (DAT);
/* Perform inserts into MYTABLE where some DAT are null */
SELECT COUNT(*) FROM MYTABLE WHERE DAT IS NULL;
The ending SELECT will not be able to use the index, because the leafs (right-most column) will not capture the nulls. Burleson's solution is stupid, because now you have to use a NVL in all your queries and have compromised the data in the tables. Gorbachev's method includes a known NOT NULL column for the leaves of the b-tree, but this expands the index for no reason. Maybe in his case the index made sense that way for tuning other queries, but if all you want to do is find the NULLs then the easiest solution is to make the leaf a constant.
CREATE INDEX MYTABLE_IDX_1 ON MYTABLE (DAT, 1);
Now, the leaves are all the constant (1), and by default the nulls will all be together (either at the top or bottom of the index, but it doesn't really matter as Oracle can use the index forwards or backwards). There is a slight storage penalty for that constant, but a single number is smaller than most other data fields in a typical table. Now the database can use the index when querying for nulls...if the optimizer finds that the best way to get the data.

SQL Server 2008 search for date

I need to search rows entered on a specific date.
However the datatype of column I need to search on is datetime, and the datatype of argument is Date.
I can use the the query like
Select result
from table
where
convert(date, Mycolumn) = #selectedDate
but this would affect the SARGability of the query and will not use indexes created on mycolumn.
I was trying to use the following query:
Select result
from table
where
Mycolumn
BETWEEN #selectedDate AND Dateadd(s, -1, Dateadd(D, 1, #selectedDate))
However this does not work since the #selectedDate is Date type and a second can't be added or removed.
Can someone help me with a working query?
Thanks.
It is my understanding that using:
convert(date, Mycolumn) = #selectedDate
is SARGable. It will use the index on Mycolumn (if one exists). This can easily be confirmed by using the execution plan.
Select result
from table
where
Mycolumn >= #selectedDate
AND Mycolumn < Dateadd(D, 1, #selectedDate)
If you need to do these searches a lot, you could add a computed, persisted column that does the conversion to DATE, put an index on it and then search on that column
ALTER TABLE dbo.YourTable
ADD DateOnly AS CAST(MyColumn AS DATE) PERSISTED
Since it's persisted, it's (re-)calculated only when the MyColumn value changes, e.g. it's not a "hidden" call to a stored function. Since it's persisted, it can also be indexed and used just like any other regular column:
CREATE NONCLUSTERED INDEX IX01_YourTable_DateOnly ON dbo.YourTable(DateOnly)
and then do:
SELECT result FROM dbo.YourTable WHERE DateOnly = #SelectedDate
Since that additional info is stored in the table, you'll be using a bit more storage - so you're doing the classic "space vs. speed" trade-off; you need a bit more space, but you get more speed out of it.

Resources