Using dummy condition to make sure multi-column index is used? - sql

Let's say I have a database table with a multi-column index on columns (A, B, C). I want to do a
SELECT ... WHERE C BETWEEN c1 AND c2
which is slow because the index does not get used.
Does it make any sense to try and 'fool' SQL Server into using the index by including dummy conditions on A and B? I.e.:
SELECT ... WHERE ((A >= MIN_VALUE) OR A IS NULL)
AND ((B >= MIN_VALUE) OR B IS NULL)
AND (C BETWEEN c1 AND c2)
I cannot modify the table in any way.

A multi-column index on (A, B, C) is not going to be used for a condition that is only on C.
Your attempt to "fool" SQL Server indicates that you don't fully understand how indexes work. Indexes are applied to conditions up-to and including the first inequality (actually, anything other than = or is null).
MySQL actually has a pretty good explanation of how multi-column indexes are used. What it says is generally true across databases (although some databases -- but not SQL Server -- have an additional operation called skip-scan which could be used in some additional cases).
Your index could be used for:
where A = #A and B = #B and C between #c1 and #c2
An index is not going to be used if c1 and c2 are columns in a table. (Well, it might be used in a full index scan but not a lookup/seek.)

Related

Composite Indexes, the “Include” Keyword, and How They Work

In SQL Server (and most other relational databases), a "Composite Index" is an index with multiple keys. Let's say we have this query that gets run a lot, and we want to create a covering index for this query to speed it up;
SELECT a, b FROM MyTable WHERE c = #val1 AND d = #val2
These are all possible composite indexes that would cover this query;
CREATE INDEX ix1 ON MyTable (c, d, a, b)
CREATE INDEX ix2 ON MyTable (c, d) INCLUDE (a, b)
CREATE INDEX ix3 ON MyTable (d) INCLUDE (a, b, c)
CREATE INDEX ix4 ON MyTable (c) INCLUDE (a, b, d)
But apparently, they don't perform equally. According to Erlan Sommarskog (Microsoft MVP), the first two are faster than the 3rd and 4th, and the 4th is faster than the 3rd.
He goes on to explain;
ix2 is the "best" index, because a and b will not take up space in the higher levels of the index tree. Also, if a or b are updated, in ix2 there can be no page splits or similar as the index tree is unaffected.
However, I am having a hard time grasping what exactly is going on. I do have the general knowledge on b-tree indexes and how they work, but I don't understand the logic behind composite keys. For example;
CREATE INDEX ix1 ON MyTable (c, d, a, b)
Does the order of the columns here matter? If so, why? Also;
CREATE INDEX ix2 ON MyTable (c, d) INCLUDE (a, b)
What is the difference between this composite key and the one above? I don't understand what difference "INCLUDE" makes.
Note: I know there are a lot of posts on Composite Keys, but I believe my last two questions are specific enough to not be a duplicate.
Does the order of the columns here matter?
Considering only the query in your question with 2 equality predicates, the order of the composite index key columns doesn't matter as long as both are the leftmost key columns of the composite index. Any of the covering indexes below will optimize this query:
CREATE INDEX ix1 ON MyTable (c, d, a, b);
CREATE INDEX ix2 ON MyTable (c, d) INCLUDE (a, b);
CREATE INDEX ix3 ON MyTable (d, c, a, b);
CREATE INDEX ix4 ON MyTable (d, c, b, a);
CREATE INDEX ix5 ON MyTable (d, c) INCLUDE (a, b);
That said, the stats histogram contains only the leftmost index key column so the general guidance is to specify the most selective column first to improve row count estimates and execution plan quality. This consideration is more important for non-trivial queries where the optimizer has many choices and row count estimates are an important factor in choosing the best plan.
Another consideration for key order, which may conflict with the above general guidance, is when the index supports different queries and only some of the key columns are specified (e.g. SELECT a, b FROM MyTable WHERE d = #val2;). In that case, it would be better to specify d as the leftmost column regardless of selectivity in order to allow a single index to optimize multiple queries instead of creating a separate index to optimize the second query.
What is the difference between this composite key and the one above? I
don't understand what difference "INCLUDE" makes.
Included columns are not key columns. Key columns are maintained in logical order at every level throughout the b-tree whereas included columns are present only in the b-tree leaf nodes and not ordered. Consequently, the specified order of included columns does not matter. The only purpose of included columns is to help cover queries without adding them as key columns and incurring the associated overhead.
CREATE INDEX ix1 ON MyTable (c, d, a, b)
Does the order of the columns here matter? If so, why? Also;
Yes, order is very important while creating index, because each column is (from left) next level of deepness in index, so to determine the compilator to use this index you need always seek for c which is the "opener" of this set.
CREATE INDEX ix2 ON MyTable (c, d) INCLUDE (a, b)
What is the difference between this composite key and the one above? I don't understand what difference "INCLUDE" makes.
But keep in mind that for each level of the index it starts to be less efficient, so if you know that > 80% of your queries will only seek by c & d and not a & b, but you will need that information in your SELECT (nor in WHERE) you should INCLUDE them, as part of the leaf at the last level of the index.
There are better explanations than mine so feel free to look at them:
INCLUDE equivalent in Oracle -> INCLUDE
How important is the order of columns in indexes? -> ORDER in INDEX set

Oracle multiple vs single column index

Imagine I have a table with the following columns:
Column: A (numer(10)) (PK)
Column: B (numer(10))
Column: C (numer(10))
CREATE TABLE schema_name.table_name (
column_a number(10) primary_key,
column_b number(10) ,
column_c number(10)
);
Column A is my PK.
Imagine my application now has a flow that queries by B and C. Something like:
SELECT * FROM SCHEMA.TABLE WHERE B=30 AND C=99
If I create an index only using the Column B, this will already improve my query right?
The strategy behind this query would benefit from the index on column B?
Q1 - If so, why should I create an index with those two columns?
Q2 - If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?
The simple answers to your questions.
For this query:
SELECT *
FROM SCHEMA.TABLE
WHERE B = 30 AND C = 99;
The optimal index either (B, C) or (C, B). The order does matter because the two comparisons are =.
An index on either column can be used, but all the matching values will need to be scanned to compare to the second value.
If you have an index on (B, C), then this can be used for a query on WHERE B = 30. Oracle also implements a skip-scan optimization, so it is possible that the index could also be used for WHERE C = 99 -- but it probably would not be.
I think the documentation for MySQL has a good introduction to multi-column indexes. It doesn't cover the skip-scan but is otherwise quite applicable to Oracle.
Short answer: always check the real performance, not theoretical. It means, that my answer requires verification at real database.
Inside SQL (Oracle, Postgre, MsSql, etc.) the Primary Key is used for at least two purposes:
Ordering of rows (e.g. if PK is incremented only then all values will be appended)
Link to row. It means that if you have any extra index, it will contain whole PK to have ability to jump from additional index to other rows.
If I create an index only using the Column B, this will already improve my query right?
The strategy behind this query would benefit from the index on column B?
It depends. If your table is too small, Oracle can do just full scan of it. For large table Oracle can (and will do in common scenario) use index for column B and next do range scan. In this case Oracle check all values with B=30. Therefore, if you can only one row with B=30 then you can achieve good performance. If you have millions of such rows, Oracle will need to do million of reads. Oracle can get this information via statistic.
Q1 - If so, why should I create an index with those two columns?
It is needed to direct access to row. In this case Oracle requires just few jumps to find your row. Moreover, you can apply unique modifier to help Oracle. Then it will know, that not more than single row will be returned.
However if your table has other columns, real execution plan will include access to PK (to retrieve other rows).
If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?
Yes. Please check the details here. If index have several columns, than Oracle will sort them according to column ordering. E.g. if you create index with columns B, C then Oracle will able to use it to retrieve values like "B=30", e.g. when you restricted only B.
Well, it all depends.
If that table is tiny, you won't see any benefit regardless any indexes you might create - it is just too small and Oracle returns data immediately.
If the table is huge, then it depends on column's selectivity. There's no guarantee that Oracle will ever use that index. If optimizer decides (upon information it has - don't forget to regularly collect statistics!) that the index should not be used, then you created it in vain (though, you can choose to use a hint, but - unless you know what you're doing, don't do it).
How will you know what's going on? See the explain plan.
But, generally speaking, yes - indexes help.
Q1 - If so, why should I create an index with those two columns?
Which "two columns"? A? If it is a primary key column, Oracle automatically creates an index, you don't have to do that.
Q2 - If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?
If you are talking about a composite index (containing both B and C columns, respectively), and if query uses B column, then yes - index will (OK, might be used). But, if query uses only column C, then this index will be completely useless.
In spite of this question being answered and one answer being accepted already, I'll just throw in some more information :-)
An index is an offer to the DBMS that it can use to access data quicker in some situations. Whether it actually uses the index is a decision made by the DBMS.
Oracle has a built-in optimizer that looks at the query and tries to find the best execution plan to get the results you are after.
Let's say that 90% of all rows have B = 30 AND C = 99. Why then should Oracle laboriously walk through the index only to have to access almost every row in the table at last? So, even with an index on both columns, Oracle may decide not to use the index at all and even perform the query faster because of the decision against the index.
Now to the questions:
If I create an index only using the Column B, this will already improve my query right?
It may. If Oracle thinks that B = 30 reduces the rows it will have to read from the table imensely, it will.
If so, why should I create an index with those two columns?
If the combination of B = 30 AND C = 99 limits the rows to read from the table further, it's a good idea to use this index instead.
If I decided to create an index with B and C, If I query selecting only B, would this one be affected by the index?
If the index is on (B, C), i.e. B first, then Oracle may find it useful, yes. In the extreme case that there are only the two columns in the table, that would even be a covering index (i.e. containing all columns accessed in the query) and the DBMS wouldn't have to read any table row, as all the information is already in the index itself. If the index is (C, B), i.e. C first, it is quite unlikely that the index would be used. In some edge-case situations, Oracle might do so, though.

Maximum number of useful indexes a table can have?

The Meeting
In a meeting last week the client was discussing how to make an important search page faster. The page searches on a single table (12 columns, 20 million rows) by asking for values (strings) on any field; it returns 50 rows (with pagination), starting with the specified criteria (each column can be ascending or descending). When the criteria doesn't match the existing indexes, the search becomes slow, and the client is not happy.
And then -- in the middle of the meeting -- the semi-technical analyst threw this one into the air: Why don't we create all possible indexes on the table to make everything fast?
I responded at once "No, there are too many and that would make the table really slow to modify, so we need to create few cleverly chosen indexes to do it". We ended up creating the most useful ones, and the page is now much faster. Problem solved.
The Question
But still... I keep thinking about that question and I wanted to have a better understanding of it, so here it is:
In theory, how many possible useful indexes can I create on a table with N columns?
I think that by useful we should consider (I can be wrong):
Indexes not already covered by other ones: for example (a, b) should not be counted if (a, b, c) is included.
In order to show multiple rows (not just equality) ascending and descending indexes should be counted as separate ones when they are part of a composite index. That is: (a) serves the same purpose of (a DESC), but (a, b) serves a different purpose than (a DESC, b).
So, a table with a single column (a) can have only a single index:
(a)
With two columns (a, b) I can have four useful indexes:
(a, b)
(b, a)
(a DESC, b)
(b DESC, a)
(a) -- already covered by #1
(b) -- already covered by #2
(a, b DESC) -- already coverred by #1 (reading index in reverse)
(b, a DESC) -- already covered by #2
(a DESC, b DESC) -- already covered by #3
(b DESC, a DESC) -- already covered by #4
(a DESC) -- already covered by #3
(b DESC) -- already covered by #4
With three columns (a, b, c):
(a, b, c)
(a, c, b)
(b, c, a)
(b, a, c)
(c, a, b)
(c, b, a)
...
Let's say you have a table t with columns a, b, and c.
For the query
select a from t where b = 1 order by c;
the best index is on t(b,c,a), because you first look up values using b, then order results by c and have a in the results.
For this query:
select a from t where c = 1 order by b;
the best index is on t(c,b,a).
For this query:
select b from t where c = 1 order by a;
the best index is on t(c,a,b).
With more columns a query could look like this:
select a from t where b = 1 order by c, d, e;
and you'd best want an index on t(b,c,d,e,a).
While for
select a from t where b = 1 order by e, d, c;
you'd want an index on t(b,e,d,c,a).
So the maximal number of useful indexes for n columns is n!, i.e. all permutations.
This is for indexes on the mere columns alone. As Gordon Linoff has mentioned in the comments section to your request, you may also want function indexes (e.g. on t(upper(a),lower(b)). The number of usefull function indexes is theoretically unlimited. And yes, Gordon is also right about further index types.
So the final answer is that theoretically the number of useful indexes per table is unlimited.
All the other answers contain something valuable, but there is enough that I have to say about it to warrant a third one.
There is no exact answer to the question like you put it. In a way, it is like asking “What's the limit beyond which you would call a person crazy?” There is a large grey area.
My points are:
What would happen if you add too many indexes:
Modifying the table gets substantially slower. Even with few indexes, data manipulation will already become an order of magnitude slower. If you ever want to INSERT, UPDATE or DELETE, a table with all conceivable indexes would make such an operation glacially slow.
With many indexes, the query planner has to consider many different access paths, so planning the query will become slightly slower with any index you add. With very many indexes, it may well be that the planning overhead will make the query too slow even before the executor has started working.
What can you do to reduce the number of indexes needed:
Look at the operators. If the operators <, <=, >= and > are never used, there is no point in adding indexes with descending columns.
Remember that an index on (a, b, c) can also be used for a query that only uses a in its condition, so you don't need an extra index on (a).
What is a practical way forward for you?
I have two suggestions:
One way it to add a simple index on each of your twelve columns.
Twelve indexes are already quite a lot, but you are still not in the crazy range.
PostgreSQL can use these indexes efficiently in a query with conditions on more than one column, and even if none of the conditions alone would be selective enough to warrant an index scan.
This is because PostgreSQL has bitmap index scans. See this example from the documentation:
EXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000;
QUERY PLAN
-------------------------------------------------------------------------------------
Bitmap Heap Scan on tenk1 (cost=25.08..60.21 rows=10 width=244)
Recheck Cond: ((unique1 < 100) AND (unique2 > 9000))
-> BitmapAnd (cost=25.08..25.08 rows=10 width=0)
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=101 width=0)
Index Cond: (unique1 < 100)
-> Bitmap Index Scan on tenk1_unique2 (cost=0.00..19.78 rows=999 width=0)
Index Cond: (unique2 > 9000)
Each index is scanned and a bitmap is formed that contains 1 for each row that matches the condition. Then the bitmaps are combined, and finally the rows are fetched from the table.
The other idea is to use a Bloom filter.
If the only operator in your conditions is =, you can
CREATE EXTENSION bloom;
and create a single index USING bloom over all table columns.
Such an index can be used for queries with any combination of columns in the WHERE clause. The down side is that it is a lossy index, so you will get false positive results that have to be fetched and filtered out.
It depends on your case, but this might be an elegant (and underestimated!) solution that balances query and update speed.
In theory, how many possible useful indexes can I create on a table with N columns?
Rather than answering this question theoretically, a practical answer is much better.
The first point to note is that all sequential searches should be avoided (unless the table is very small). By "very small", I mean, just a few rows (say, max 10). (However, even in such a table, a primary key is encouraged, to enforce uniqueness. This would, of course, be implemented as an index.)
Therefore, if the client has a valid search path, an index is required. If an existing index serves the purpose, that's OK; else, in all probability, an additional index is needed.
One transaction table in one application in my experience had 8 indexes. The client insisted on certain search paths, and so we had no choice but to provide them. Of course, we informed the client that updates would slow down, but the client found that acceptable. In reality, the slowdown in speed during updates wasn't appreciable.
So that is the approach suggested - warn the client accordingly.
It is important to verify, during design, that a SQL statement uses indexed search paths (for every accessed table), rather than searching sequentially. ORACLE has a tool for this, called EXPLAIN PLAN. Other DBs should also have similar tools.

Best indexes to create when a search may be on any or all of 3 fields

I am working on a new search function in our software where a user will be allowed to search on any or all of 3 possible fields A, B and C. I expect that if anything is entered for a field it will be a complete entry and not just a partial one.
So the user choices are
Field A, or
Field B, or
Field C, or
Fields A & B, or
Fields A & C, or
Fields B & C, or
Fields A, B & C.
My question is what indexes should be created on this table to provide maximum performance? This will be running on SQL Server 2005 and up I expect and a good user experience is essential.
this is difficult to answer without knowing your data or its usage. Hopefully A, B , and C are not long string data types. If you have minimal Insert/Update/Delete and/or will sacrifice everything for index usage, I would create an index on each of these:
A, B , C <<<handles queries for: A, or A & B, or A, B & C
A, C <<<handles queries for: A & C
B, C <<<handles queries for: B, or B & C
C <<<handles queries for: C
These should cover all combinations you have mentioned.
Also, you will also need to be careful to write a query that will actually use the index. If you have an OR in your WHERE you'll probably not use an index. In newer versions of SQL Server than you have you can use OPTION(RECOMPILE) to compile the query based on the runtime values of local variables and usually eliminate all OR and use an index. See:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
you can most likely use a dynamic query where you only add the necessary conditions onto the WHERE to get optional index usage:
The Curse and Blessings of Dynamic SQL by Erland Sommarskog
You can also see this answer for more on dynamic search conditions
Assuming searches are much more numerous, you will want to create an index on every subset of fields by which you wish to access your data. So that would be 6 indices if you wish to do it on the powerset of columns.
I would recommend this basic approach.
1) Make sure your table has a clustered index which is Unique, Ascending, and Small (ideally an INT).
2) Create the following three non-clustered indexes:
CREATE NONCLUSTERED INDEX ON dbo.YourTable(a) INCLUDE (b,c, [plus any potential output columns])
CREATE NONCLUSTERED INDEX ON dbo.YourTable(b) INCLUDE (a,c, [plus any potential output columns])
CREATE NONCLUSTERED INDEX ON dbo.YourTable(c) INCLUDE (a,b, [plus any potential output columns])
3) Use the index DMVs to compare the times each index is hit. If an index is used heavily, experiment by adding two more indexes. (Assume the index with C as a single tree node is the heavily used index.)
CREATE NONCLUSTERED INDEX ON dbo.YourTable(c,a) INCLUDE (b, [plus any potential output columns])
CREATE NONCLUSTERED INDEX ON dbo.YourTable(c,b) INCLUDE (a, [plus any potential output columns])
Compare how frequently they're used verses the single tree node index. If they're not being used infavor of the single tree node, they may be superfluous.
In summary, start with a minimal covering indexes and experiment based on usage.

Do covering indices safely replace smaller covering indices?

For example:
Given columns A,B,C,D,
IX_A is an index on 'A'
IX_AB is a covering index on 'AB'
IX_A can be safely removed, for it is redundant: IX_AB will be used in its place.
I want to know if this generalizes:
If I have:
IX_AB
IX_ABC
IX_ABCD
and so forth,
Can the lesser indices still be safely removed?
That is, does IX_ABC make IX_AB redundant, and does IX_ABCD make both IX_AB and IX_ABC redundant?
In general -- and this varies from server to server -- a covering index will cover smaller-selections of the index.
So if you have an index that covers a, b, c, that usually automatically gives you an index that covers a, and a, b.
You are not guaranteed to have, for example, a covering index of b, c.
Yes, for the most part.
However, IX_ABCD isn't terribly helpful as a replacement for, say, IX_BCD.
There is a caveat, however: indexes still may require disk reads, so if C and D explode the size of the index, there will be some inefficiency in looking up A,B in IX_ABCD that wouldn't occur when looking it up in IX_AB.
However, that difference is likely outweighed by the additional performance hit of maintaining IX_AB separately.
The important thing is the leading columns in the index. If you have the index IX_ABCD the following queries will use the index:
select * from table where A = 1
select * from table where A = 1 and B = 1
select * from table where A = 1 and B = 1 and C = 1
However, the following will most likely not uses the index (at least not how you intended):
select * from table where B = 1
select * from table where C = 1
select * from table where B = 1 and C = 1
The important thing is that the leading columns are used. Therefore the order of the columns when the index is created does matter.
Not necessarily. While is true that an index on (A, B, C) can be used for a filtering predicate on A or an ordering request on A or a join condition on A, that does not necessarily mean that the index (A) alone is useless. If the index on (A, B, C) is considerably wider than (A), then a range scan on A alone will save significant I/O because it would have to read fewer pages (narrower index).
ut I admint that this would be the exception rather than the rule. In general is safe to remove an index on A if another one on (A, B) exists. Note that an index on (A,B) does not satisfy any filtering on B so, is safe to remove only if the leftmost column(s) are the same. Some databases have 'skip-scan' operators that can use an index on (A,B) for looking up B, but that is a very narrow border case.
Always best not to assume anything about database engine internals and actually check the actual query plans being used.