Abstract

Indexes can be created on the result of a function applied to columns in a table. That can be useful in a variety of ways, such as fast case-insensitive searching on character data. There is also a particular solution explored using built-in function “ifx_checksum” for very compact indexes on columns wider than normally allowed.

Content

Examples in this article were produced using the provided “stores_demo” database in a Docker container from informix-dockerhub with Informix Dynamic Server (IDS) updated to 14.10.FC11.

Functional indexes are documented here. For example, you might want to search rapidly through a character column beginning with supplied text in either lower or upper case (without installing the Basic Text Search extension). The following table was created to test this, with alternate rows upshifted:

Copy to Clipboard


This SQL uses built-in function UPPER to get the required results:

Copy to Clipboard


The results are:

Copy to Clipboard


However, the query plan is:

Copy to Clipboard


That would be a problem on a large table as it would scan all rows.

You might then try and fail to create an index on the built-in function:

Copy to Clipboard


You can only create an index on a user-defined function. This can be a stored procedure language (SPL) function, so we can create a simple wrapper function:

Copy to Clipboard
  • You must declare the function as invariant, meaning it will always return the same output for given input.
  • Index keys have a limit on the total number of bytes, so set a sensible length on the input and output.
  • Use TRIM in case the intput data is CHAR to discard trailing spaces.

We can now create a functional index:

Copy to Clipboard


Retesting as follows returns the same results:

Copy to Clipboard


This time, the query plan contains:

Copy to Clipboard


Having seen the basics of functional indexes for fast case-insensitive queries, we can now look at the second purpose of this article. What if we need to index a wide column set which might require excessive disk space and/or exceed the allowed limits? The following example on the “stores_demo” database is based on a real case where a unique index was reduced from 14GB to 1GB.

The “stores_demo” database contains a table with the following schema:

Copy to Clipboard


Note that LVARCHAR is equivalent to LVARCHAR(1024).

Firstly, we might want to make “warehouse_id” a unique SERIAL number as probably intended:

Copy to Clipboard


Let’s say we then want to make “warehouse_name” unique. The obvious solution fails:

Copy to Clipboard


More details on any error number can be obtained with “finderr” as in this case:

Copy to Clipboard


Fortunately, there is a built-in function “ifx_checksum” we can use that is described here:

https://docs.deistercloud.com/content/Databases.30/IBM Informix.2/Tips/Checksum.xml?embedded=true

IBM and HCL Informix documentation refer to it in the context of Enterprise Replication, but does not otherwise cover it.

We can create the index with:

Copy to Clipboard
  • The index cannot be unique as there could be checksum collisions, so uniqueness must be enforced by triggers.
  • IDS 11.70+ supports the ONLINE keyword to create an index while the table is in use.

If you are creating more than one checksum index, you might need different variations of “sp_checksum” with varying data types and numbers of parameters. Those with more than one would have a combined checksum expression as in this example:

Copy to Clipboard


Once you have functional indexes, you will be prevented from dropping the function:

Copy to Clipboard


Experience shows that a separate function to check rapidly whether a row already exists is more useful in a separate function, so it can be used both in triggers and applications:

Copy to Clipboard
  • There should be a parameter for each column in the index (one in our example).
  • An optional last parameter is needed for triggers to ignore the row being checked.
  • Optimizer directive +INDEX ensures the checksum index will be used.
  • The warehouse name must match as well as the checksum in case of collision.
  • A third condition is present to ignore the specified row if provided for triggers.

We can now create the trigger procedure:

Copy to Clipboard


The triggers are then as follows:

Copy to Clipboard

TIP: set undocumented parameter NONEXCLTRIG so you can drop or create triggers while the table is in use.

You should now find that you cannot create duplicates in “warehouse_name”:

Copy to Clipboard
Copy to Clipboard

Conclusion

The techniques in this article can provide fast fuzzier searches, and massively reduce the space required to index wide column sets.

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.

Contact Us

If you have any questions or would like to find out more about this topic, please contact us.

Author