Abstract
Updated July 2024
Thanks to Andreas Ledger, RFE INFX-I-368 has been delivered, and this feature is now available in all IDS Editions from version 14.10.FC11 onwards.
Updated February 2026
The procedure provided to generate implementation SQL now fully handles foreign key constraints and has new parameters.
Best practice has always been not to create indexes on highly duplicate data. Scanning the entire table for a common value may be quicker, and updating an index can be very costly when many pointers to rows with the same value are spread over several pages. A work-around when an index is essential in this scenario is to extend the index with a more selective column, but this obviously makes it bigger.
For the first time, a far better solution was provided in IDS 14.10.FC2, known as Partial Indexes (click for the relevant page in the IBM Knowledge Center).
In this article, we will demonstrate how to identify where such indexes might be appropriate, how to create them, and how much smaller they can potentially be.
Content
A classic example is the index on the “status” column of the Sage Line 500 “opheadm” table which contains sales orders. 99% of rows will typically have the value “8” for “Invoiced” in the status column: if we wanted to retrieve all those rows, the query optimizer will probably find it quicker to scan the whole table without using any index. However, most of the time, we are looking for rows with one of the other values, for which we do need an index. The following simulates the scenario (the real table obviously has many more columns):
That returns:
| status | number |
|---|---|
| 1 | 1000 |
| 2 | 1000 |
| 3 | 1000 |
| 4 | 1000 |
| 5 | 1000 |
| 6 | 1000 |
| 7 | 1000 |
| 8 | 993000 |
The standard index has 2783 used pages, 2766 leaves, and 3 levels.
SQL to replace this with a partial index excluding invoiced rows is:
- Stating the dbspace name before “INDEX OFF” is recommended as it’s necessary for mixed page sizes: see Caveats.
- Partition names can be whatever you like instead of “part_0” and “part_1” within the normal Informix object name rules.
The new index has 24 used pages, 22 leaves, and 2 levels.
The following function helps you identify indexes that could be candidates, and generates SQL to replace them with partial indexes:
It checks all duplicate indexes on single columns in a specified database to see if there are values accounting for more than a given percentage of rows in the table. For example, create and populate the example table as described in the IBM Knowledge Center Partial Indexes page, but with this index:
Then run the new function:
SQL generated:
The number of leaves, levels and rows is shown so that you can decide which indexes are big enough to matter, plus the largest percentage of rows with a column value to be excluded from the index
Run on the standard demo database:
SQL generated:
Additional statements are required for indexes supporting foreign keys. The constraint must be dropped first, without which we cannot rebuild the index. There are two scenarios regarding whether we also need to drop the index explicitly:
- If the index was previously created automatically by an ADD CONSTRAINT statement, it is hidden and has a name beginning with a space followed by the table ID and a sequential number. It will be dropped with the constraint. In order to recreate it separately before the constraint is added back, it must have a valid name that does not begin with a space, so the procedure replaces the leading space with “ix_”.
- If the index was previously created explicitly before an ADD CONSTRAINT statement, it must be dropped explicitly after the constraint.
The procedure handles all of that. You will also find that the generated SQL always begins with:
That makes it way quicker to recreate constraints, as it doesn’t then pointlessly recheck column values in the referenced table: they must have been there just before when the constraint already existed.
The full set of parameters are:
- Database if different to where the function is defined
- Percentage of rows for a column value to be a candidate (default 50%)
- Minimum number of rows for the table to be included (default 1000)
- Skip indexes supporting foreign key constraints (default off)
You may want to experiment with different thresholds in 2 and 3. We recommend using the defaults as a starting point, but you can change those in the code as is suitable for your system:
- 50% means you will only ever have one column value listed, which keeps it simple, and is a good compromise between saving space but still indexing values that might have a purpose.
- Less than 1000 rows is the normal definition of a “small table” for Automated Update Statistics and the Query Optimizer. The index will quite likely not be used and its size will be trivial, so we might as well exclude it from the generated SQL to keep it shorter.
Caveats
Tables comprised of multiple fragments (partitions) is part of the parallelisation features normally reserved for Enterprise Edition. Partial indexes have been implemented using the same FRAGMENT BY EXPRESSION (or PARTITION) syntax, and this was rejected on lower editions (except Developer) with error 26453 “Fragmentation is not supported in this edition of IDS” prior to 14.10.FC11.
This article was updated in August 2020 with new information from Roland Wintgen who opened a case with IBM. A problem occurs if the database or table is in a dbspace with a non-default page size. For example, in an instance with 2KB pages by default, if you create a 4KB page dbspace “data4kb” then a new database in it, the following simpler form of SQL for one of our examples produces an error:
You have to declare a dbspace name for both fragments in this situation. Perhaps it otherwise defaults to the root dbspace, causing the error. However, it still fails:
The solution is also to name the fragments (aka. partitions):
The stored procedure and examples in this article were amended accordingly. If accepted as a bug by IBM, we will provide further updates here with the defect number and IDS version containing the fix when either are known. Meanwhile, the above is a full work-around.
Conclusion
If Informix 14.10 Partial Indexes are available in your version and edition, they may save you considerable disk space and make reads, inserts and deletes lighter.
Disclaimer
Suggestions above are provided “as is” without warranty of any kind, either express or implied, including without limitation any implied warranties of condition, uninterrupted use, merchantability, fitness for a particular purpose, or non-infringement.