How to find references to a particular index? - sql

How do I find all DB references (such az INDEX optimizer hints) to a particular index?
(I plan to drop an index, and need to know whether it has any dependant objects associated.)

Especially, This sql_text column of this sql may be helpful for an individual index :
select p.sql_id, q.sql_text, p.access_predicates
from gv$sql_plan p
inner join gv$sql q on ( p.sql_id = q.sql_id )
where p.object_name = upper('&i_index_name')
group by p.access_predicates, q.sql_text, p.sql_id
order by p.access_predicates, q.sql_text, p.sql_id;

An Index does not have any dependencies. An Index is based on table(s) and column(s). If you like to know whether an index was used by any query you can use Index Monitoring feature.
You can enable/disable monitoring by
ALTER INDEX my_index_i MONITORING USAGE;
ALTER INDEX my_index_i NOMONITORING USAGE;
Then you can check index usage in view v$object_usage(for release 12.1 and less) or dba_object_usage

Related

What Columns Should I Index to Improve Performance in SQL

In my query I have a temp table of keys that will be joined to multiple tables later on.
I want to create an index on my temp table to improve performance, cause it takes a couple of minutes for my query to run.
SELECT DISTINCT
k.Id, k.Name, a.Address, a.City, a.State, a.Zip, p.Phone, p.Fax, ...
FROM
#tempKeys k
INNER JOIN
dbo.Address a ON a.AddrId = k.AddrId
INNER JOIN
dbo.Phone p ON p.PhoneId = a.PhoneId
...
My question is should I create an index for each column that is being joined to a table separately
CREATE NONCLUSTERED INDEX ... (Addr.Id ASC)
CREATE NONCLUSTERED INDEX ... (PhoneId ASC)
or can I create one index that includes all columns being joined
CREATE NONCLUSTERED INDEX ... (Addr.Id ASC, PhoneId ASC)
Also, are there other ways I can improve performance on this scenario?
As #DaleK says this is a complex topic. In general though, an index is only usable when all the leading values are used. Your suggestion of a composite index will likely not work. The indexed value of PhoneId cannot be used independently from AddrId. (The index would be ok for AddrId on its own)
The best approach is to have a test database with representative data & volumes then check the query plan & suggestions. Don't forget every index you add has a side effect on the insert.
Another factor is that without a WHERE clause or if there are larger data sets (I think over 5-10% of the table), the optimiser will decide it's often faster to not use indexes anyway.
And I'd rethink using temp tables anyway, let alone indexed ones. They're rarely necessary. A single, large query usually runs faster (and has better data integrity depending on your isolation model) than one split into chunks.

Do I have a redundant index in this SQLite schema?

I created an SQLlite schema as follows:
CREATE TABLE tab1 (
year INTEGER,
tar_id TEXT,
content BLOB,
UNIQUE (year, tar_id) ON CONFLICT REPLACE);
CREATE INDEX tab1_ix1 ON bcas (year, tar_id);
Then I looked at a query plan:
sqlite> explain query plan select * from tab1 where tar_id = 1 and year = (select max(year) from tab1 where year < 2019 and tar_id = 1);
QUERY PLAN
|--SEARCH TABLE tab1 USING COVERING INDEX sqlite_autoindex_tab1_1 (year=? AND tar_id=?)
`--SCALAR SUBQUERY
`--SEARCH TABLE tab1 USING COVERING INDEX tab1_ix1 (year<?)
It seems to me that only one index would be sufficient to do this, but it uses both my explicit tab1_ix1 and and automatically generated sqlite_autoindex_tab1_1.
Is one of them redundant? If so, how do I get rid of one of them and get the same behaviour?
Yes, you have a redundant index. A unique constraint generates an index automatically. You do not need to create another one explicitly index for the same columns in the same order.
Note that an index on (tar_id, year) would be a different index, because the ordering of keys in the index matters.
Although both seam redundant but there is some detail to be focused. In first part of query "*" is used so the auto created candidate is best suited because it links all other columns to retrieve. While in second portion with "max" clause only two columns (year, tar_id) are under consideration and they are all present with needed sequence in "smaller" manually created index "tab1_ix1" and engine thinks smaller being efficient so it uses tab1_ix1 this time.
So the default auto created index will be utilized by engine if slight degradation in performance is affordable and second smaller tab1_ix1 seem burden maintenance wise.

SQL Server non-clustered index

I have two different queries in SQL Server and I want to clarify
how the execution plan would be different, and
which of them is more efficient
Queries:
SELECT *
FROM table_name
WHERE column < 2
and
SELECT column
FROM table_name
WHERE column < 2
I have a non-clustered index on column.
I used to use Postgresql and I am not familiar with SQL Server and these kind of indexes.
As I read many questions here I kept two notes:
When I have a non-clustered index, I need one more step in order to have access to data
With a non-clustered index I could have a copy of part of the table and I get a quicker response time.
So, I got confused.
One more question is that when I have "SELECT *" which is the influence of a non-clustered index?
1st query :
Depending on the size of the data you might face lookup issues such as Key lookup and RID lookups .
2nd query :
It will be faster because it will not fetch columns that are not part of the index , though i recommend using covering index ..
I recommend you check this blog post
The first select will use the non-clustered index to find the clustering key [clustered index exists] or page and slot [no clustered index]. Then that will be used to get the row. The query plan will be different depending on your STATS (the data).
The second query is "covered" by the non-clustered index. What that means is that the non-clustered index contains all of the data that you are selecting. The clustering key is not needed, and the clustered index and/or heap is not needed to provide data to the select list.

SQL Server : is it possible to create non-clustered index for IS NULL condition

What will be the syntax to create non-clustered index for the query which has is null condition.
Sample query:
select *
from mytable
where mycolumn is null
Index that I created:
CREATE NONCLUSTERED INDEX [myindexname]
ON [dbo].[mytable] ([mycolumn])
When I execute this query in SQL and see its execution plan, it shows missing index.
Or there any other, alternative possibilities?
There is no problem creating indexes on nullable columns.
The only thing you can't do with nullable columns is create a primary key.
You can right click the green message and SSMS will give you the option to copy it. Then paste it into the query editor and you will see it contains the create index statement. All you need to do is give it it's name and run the statement.
Following the conversation in the comments to this answer, Ivan Sivak have figured out that this is a bug that SQL Server had in and was fixed in 2012 version.
Here is the link to the bug report in Microsoft Connect.
By default, the query plan uses the best index in available in any scenario.
One reason could be that the index is fragmented.
You could decrease the fragmentation by running the query
ALTER INDEX [myindexname] ON [dbo].[mytable] REBUILD;
You can read more on this here: https://learn.microsoft.com/en-us/sql/relational-databases/indexes/reorganize-and-rebuild-indexes
The query plan at times doesn't take the best available index for the query. For this, Microsoft has provided table hints.
ForceSeek
This tells the optimizer to use an index seek operation in any case.
SELECT *
FROM mytable WITH(FORCESEEK)
WHERE mycolumn IS NULL
Caution: while using any Force Plan hint (ForceSeek,ForceScan,etc.) or you might break the query
Index Hint
This tells the optimizer to use a particular index for seek/scan
SELECT *
FROM mytable WITH([myindexname])
WHERE mycolumn IS NULL
This query will now use myindexname for above query.
You can combine both these hints:
SELECT *
FROM mytable WITH([myindexname], ForceSeek)
WHERE mycolumn IS NULL
This query will now use myindexname with a scan operation for above query.
More on table hints here: https://technet.microsoft.com/en-us/library/bb510478(v=sql.105).aspx

How to optimise slow SQL query

I need a help to optimise this query. In stored procedure this part is executed for 1 hour (all procedure need 2 to execute). Procedure works for a large amount of data. Query works with two temporary tables. Both use indexes:
create unique clustered index #cx_tDuguje on #tDuguje (Partija, Referenca, Konto, Valuta, DatumValute)
create nonclustered index #cx_tDuguje_1 on #tDuguje (Partija, Valuta, Referenca, Konto, sIznos)
create unique clustered index #cx_tPotrazuje on #tPotrazuje (Partija, Referenca, Konto, Valuta, DatumValute)
create nonclustered index #cx_tPotrazuje_1 on #tPotrazuje (Partija, Valuta, Referenca, Konto, pIznos)
And this is a query:
select D.Partija,
D.Referenca,
D.Konto,
D.Valuta,
D.DatumValute DatumZad,
NULLIF(MAX(COALESCE(P.DatumValute,#NextDay)), ,#NextDay) DatumUpl,
MAX(D.DospObaveze) DospObaveze,
MAX(D.LimitMatZn) LimitMatZn
into #dwkKasnjenja_WNT
from #tDuguje D
left join #tPotrazuje P on D.Partija = P.Partija
AND D.Valuta = p.Valuta
AND D.Referenca = p.Referenca
AND D.Konto = P.Konto
and P.pIznos < D.sIznos and D.sIznos <= P.Iznos
WHERE 1=1
AND D.DatumValute IS NOT NULL
GROUP BY D.Partija, D.Referenca, D.Konto, D.Valuta, D.DatumValute
I have and Execution plan, but i am not enabled to post it here.
Just an idea: If you are permitted to do so, try to change the business logic first.
Maybe you constrain the result set only to include data from, say, a point in time back that is meaningful.
How far back in time do your account data reach? Do you really need to include all data all the way back from good old 1999?
Maybe you can say
D.DatumValute >= "Jan 1 2010"
or similar, in your WHERE clause
And this might create a much smaller temporary result set that is used in your complicated JOIN clause which will then run faster.
If you can't do this, maybe do a
"select top 1000 ... order by datum desc" query, which might run faster, and then if the user really needs to , perfomr the slow running query in a second step.
Difficult to say without haging an execution plan or some hints about number of rows in each table.
Replace this index
create nonclustered index #cx_tPotrazuje_1 on #tPotrazuje (Partija, Valuta, Referenca, Konto, pIznos)
by
create nonclustered index #cx_tPotrazuje_1 on #tPotrazuje (Partija, Valuta, Referenca, Konto, sIznos, pIznos)
The creation of indexes is a very expensive process and it could be slow sometimes, according also to the workload of the instance and to the columns involved, for which an index is created.
Furthermore, it's very difficult to say what you need to optimise, without an execution plan and without know something about the data types of the columns involved in the indexes creation.
For example, the data types of the columns Partija, Referenca, Konto, Valuta, DatumValute are not so clear.
You should tell us the data types of the columns involved in the creation of your indexes.