Wednesday, March 26, 2014

Session limit locks / limite de locks por sessão

This article is written in English and Portuguese (original version here)
Este artigo está escrito em Inglês e Português (versão original aqui)


English version:

In a very recent article I was complaining about the fact that we have some non documented features, and that from time to time those "leak" into the community. It just happened again, and this time it was the exact example I mentioned in that article. As I mentioned before, this one was already mentioned in a 2011 presentation in IOD. Now it happened in the IIUG mailing list (more precisely in the mailing list that acts as a gateway to the newsgroup comp.databases.informix), but we can also find it in a similar presentation made in IIUG 2011 conference which is available to IIUG members in their site.

I'm talking about an ONCONFIG parameter called SESSION_LIMIT_LOCKS. And yes, the name is self explanatory... It defines the maximum number of locks a session can use. Using it can be the best way to avoid a misbehaved session (or user error) to have impact on other sessions or the whole system. Since version 10 I believe (or maybe 9.4) we are able to extend the lock table. That would be a great idea but in fact it never provided the desired result. The problem was not that it doesn't work, but usually what happens is that a user does a mistake like loading millions of records into a table without locking the table, or they forget some condition in a WHERE clause of an UPDATE or DELETE instruction. So, it means that it usually won't stop after a few hundred or thousand more locks. It takes several lock table extensions, and this may consume a lot of memory. So usually the end result is one of these:

  1. The user session ends up in a long transaction (very large - exceeding LTXHWM) with a very slow rollback
  2. The system consumes a lot of memory with the abnormal lock table expansion, and the engine may end up hitting the SHMTOTAL memory limit, or overloading the machine with memory usage and consequently with swapping
Either case, it's not good.
I know about this functionality since 2011 (11.70 but I'm not sure about the fixpack) but I was under the impression that it was not fully functional. I did some tests (showed below) on 12.10.xC3 and I couldn't find any issue with it. But please consider that if it's undocumented, you won't be able to complain if it fails... In fact, I present here the tests for version 12.10.xC3. Previous versions may have different (wrong) behavior. Use it at your own risk. You will not get support!

So, let's try it:
  • I have an instance with 20000 LOCKS:
    
    castelo@primary:informix-> onstat -c | grep "^LOCKS "
    LOCKS 20000
    castelo@primary:informix-> 
    
    
  • I create a very simple test case that will consume 600 locks:
    
    castelo@primary:informix-> cat test_locks.sql
    DROP TABLE IF EXISTS test_locks;
    
    CREATE TABLE test_locks
    (
            col1 INTEGER
    ) LOCK MODE ROW;
    
    INSERT INTO test_locks
    SELECT LEVEL FROM sysmaster:sysdual CONNECT BY lEVEL < 601;
    castelo@primary:informix->
    
    
To start,  let's see how the engine is setup by default:

castelo@primary:informix-> echo "SELECT * FROM syscfgtab WHERE cf_name = 'SESSION_LIMIT_LOCKS'" | dbaccess sysmaster

Database selected.




cf_id         88
cf_name       SESSION_LIMIT_LOCKS
cf_flags      36928
cf_original   
cf_effective  2147483647
cf_default    2147483647

1 row(s) retrieved.



Database closed.

castelo@primary:informix->
 

So apparently by default it comes with (2^32) - 1 locks per session (or unlimited).
From several sources (IUG mailing list and IIUG 2011 conference presentation) we can assume this can be setup as an ONCONFIG parameter and a session variable. So let's start by trying to change the $ONCONFIG parameter:

castelo@primary:informix-> onmode -wm SESSION_LIMIT_LOCKS=100
SESSION_LIMIT_LOCKS is already set to 2147483647.
castelo@primary:informix-> 


Ops.... strange message... I tried other values and found the minimum value accepted seems to be 500:


castelo@primary:informix-> onmode -wm SESSION_LIMIT_LOCKS=500
Value of SESSION_LIMIT_LOCKS has been changed to 500.
castelo@primary:informix->

Let's verify:

castelo@primary:informix-> echo "SELECT * FROM syscfgtab WHERE cf_name = 'SESSION_LIMIT_LOCKS'" | dbaccess sysmaster

Database selected.




cf_id         88
cf_name       SESSION_LIMIT_LOCKS
cf_flags      36928
cf_original   
cf_effective  500
cf_default    2147483647

1 row(s) retrieved.



Database closed.

castelo@primary:informix->

Now we can try the test case and see what happens:

castelo@primary:informix-> dbaccess stores test_locks.sql

Database selected.


Table dropped.


Table created.


  271: Could not insert new row into the table.

  134: ISAM error: no more locks
Error in line 9
Near character position 56

Database closed.

castelo@primary:informix->

Great! If we limit to 500 locks, we cannot consume 600. That's a dream come true!
Furthermore, we can see it in online.log:

castelo@primary:informix-> onstat -m

IBM Informix Dynamic Server Version 12.10.FC3 -- On-Line -- Up 00:11:59 -- 287724 Kbytes

Message Log File: /usr/informix/logs/castelo.log

[...]

14:16:29  Maximum server connections 1 
14:16:29  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 0, Plog used 7, Llog used 2

14:16:34  Value of SESSION_LIMIT_LOCKS has been changed to 500.
14:16:39  Session SID=42 User UID=1002 NAME=informix PID=27743 has exceeded the session limit of 500 locks.

castelo@primary:informix->

Great! What else could we ask for?
Continuing with the tests... In the presentation it's also suggested that we can SET ENVIRONMENT... So:

castelo@primary:informix-> dbaccess stores <<EOF
> SET ENVIRONMENT SESSION_LIMIT_LOCKS "1000";
> EOF

Database selected.


19840: Invalid session environment variable.
Error in line 1
Near character position 41


Database closed.

castelo@primary:informix->

Ouch... it doesn't recognize the variable name... Can it be one of the reasons why it's not documented? Could be... but if we think about it, the latest session environment variables all start with IFX_ prefix and then have the $ONCONFIG parameter. So I tried with:

castelo@primary:informix-> dbaccess stores <<EOF
> SET ENVIRONMENT IFX_SESSION_LIMIT_LOCKS "1000";
> EOF

Database selected.


Environment set.



Database closed.

castelo@primary:informix->

Good! So if I add this to the test case:

castelo@primary:informix-> cat test_locks_1000.sql
DROP TABLE IF EXISTS test_locks;

CREATE TABLE test_locks
(
        col1 INTEGER
) LOCK MODE ROW;

SET ENVIRONMENT IFX_SESSION_LIMIT_LOCKS "1000";
INSERT INTO test_locks
SELECT LEVEL FROM sysmaster:sysdual CONNECT BY lEVEL < 601;
castelo@primary:informix-> dbaccess stores test_locks_1000.sql

Database selected.


Table dropped.


Table created.


Environment set.


600 row(s) inserted.


Database closed.

castelo@primary:informix->


So, this does not means it works. But the above tests had the expected result. This is the best example of the situation I described in the previous article. Resources were used to implement this and it's not currently officially available to customers, although it was previously made public at least in three situations. Hopefully this will be documented soon. I feel this is one of the most wanted features in the customer's environment. Again, this would be a nice topic to be raised at IIUG conference in Miami


Versão Portuguesa:

Num artigo muito recente queixava-me do facto de termos funcionalidades não documentadas, e que ocasionalmente informação sobre essas funcionalidades "transparecia" para a comunidade. Ora isso acabou de acontecer, e desta feita exatamente com um dos exemplos que referia no artigo. Como escrevi na altura, isto já tinha sido apresentado numa conferência IOD de 2011. Desta vez foi referido na lista de correio do IIUG (mais precisamente na lista que serve de gateway com o newsgroup comp.databases.informix), mas também é possível encontrar uma referência ao mesmo tema numa apresentação da conferência do IIUG de 2011, estando essa apresentação disponível no site do IIUG na sua área reservada a membros.

Estou a falar de um parâmetro do ONCONFIG chamado SESSION_LIMIT_LOCKS. E sim, o seu nome diz tudo... define um máximo de locks que cada sessão pode usar. Usá-lo poderá ser a melhor forma de evitar que uma sessão "mal comportada" (ou um erro de utilização) tenha impacto nas outras sessões ou mesmo no sistema em geral.
Desde a versão 10 segundo creio (ou será 9.40?) que podemos expandir a tabela de locks. Isso seria uma excelente ideia, mas na verdade julgo que nunca teve o resultado planeado. O problema não está no facto de isso não funcionar, mas antes porque habitualmente o que acontece é alguém cometer um erro como carregar milhões de registos numa tabela sem a bloquear, ou esquecer uma condição numa cláusula WHERE de um UPDATE ou DELETE. Portanto, na prática o erro deixa de abortar por falta de locks (o Informix vai expandindo a tabela) ao fim de umas centenas ou milhares de registos. O resultado passa então a ser um destes:
  1. A sessão do utilizador acaba por gerar uma transação longa (muito grande - excedendo o LTXHWM) e força um rollback geralmente demorado
  2. O sistema consome muita memória devido às expansões anormais da tabela de locks, e isso pode levar o motor a bater no limite definido pelo SHMTOTAL, ou acaba por sobrecarregar a memória da máquina e eventualmente força o sistema a entrar em swapping
Em qualquer dos casos, o resultado não é bom!
Eu tenho conhecimento desta funcionalidade sensivelmente desde 2011, salvo erro num fixpack da 11.7, mas tinha a sensação que não estava funcional. No entanto fiz alguns testes (ver abaixo) na versão 12.10.xC3 e não consegui encontrar qualquer problema. Mas tenha em conta que algo não documentado é algo sobre o qual não se poderá queixar... Na verdade, apresentarei testes com a versão 12.10.xC3. Outras versões poderão ter comportamentos diferentes (errados). Use por sua conta e risco. Não terá suporte!

Vamos tentar então:
  • Tenho uma instância com 20000 LOCKS:
    
    castelo@primary:informix-> onstat -c | grep "^LOCKS "
    LOCKS 20000
    castelo@primary:informix-> 
    
    
  • Criei um caso de teste muito simples que ao ser executado vai consumir cerca de 600 locks:
    
    castelo@primary:informix-> cat test_locks.sql
    DROP TABLE IF EXISTS test_locks;
    
    CREATE TABLE test_locks
    (
            col1 INTEGER
    ) LOCK MODE ROW;
    
    INSERT INTO test_locks
    SELECT LEVEL FROM sysmaster:sysdual CONNECT BY lEVEL < 601;
    castelo@primary:informix->
    
    
Vamos começar por ver qual é a configuração do motor por omissão:

castelo@primary:informix-> echo "SELECT * FROM syscfgtab WHERE cf_name = 'SESSION_LIMIT_LOCKS'" | dbaccess sysmaster

Database selected.




cf_id         88
cf_name       SESSION_LIMIT_LOCKS
cf_flags      36928
cf_original   
cf_effective  2147483647
cf_default    2147483647

1 row(s) retrieved.



Database closed.

castelo@primary:informix->
 

Aparentemente, a pré-configuração são (2^32) - 1 locks por sessão (ou ilimitado).
Através de várias fontes (lista de correio do IIUG e apresentação feita na conferência do IIUG de 2011), podemos assumir que a´configuração pode ser feita por parâmetro do ONCONFIG e variável de sessão. Vamos então começar por mudar o parâmetro do ONCONFIG:

castelo@primary:informix-> onmode -wm SESSION_LIMIT_LOCKS=100
SESSION_LIMIT_LOCKS is already set to 2147483647.
castelo@primary:informix-> 

Ops.... mensagem estranha... Mas eu tentei outros valores e aparentemente o mínimo que podemos definir são 500 locks:

castelo@primary:informix-> onmode -wm SESSION_LIMIT_LOCKS=500
Value of SESSION_LIMIT_LOCKS has been changed to 500.
castelo@primary:informix->

Vamos verificar:

castelo@primary:informix-> echo "SELECT * FROM syscfgtab WHERE cf_name = 'SESSION_LIMIT_LOCKS'" | dbaccess sysmaster

Database selected.




cf_id         88
cf_name       SESSION_LIMIT_LOCKS
cf_flags      36928
cf_original   
cf_effective  500
cf_default    2147483647

1 row(s) retrieved.



Database closed.

castelo@primary:informix->

Parece bem. Agora podemos tentar o caso de teste que deveria exceder os locks permitidos e ver o que acontece:

castelo@primary:informix-> dbaccess stores test_locks.sql

Database selected.


Table dropped.


Table created.


  271: Could not insert new row into the table.

  134: ISAM error: no more locks
Error in line 9
Near character position 56

Database closed.

castelo@primary:informix->

Excelente! Se definimos 500, não podemos consumir 600. Parece um sonho tornado realidade!
Mas mais ainda, podemos ver isto no online.log:

castelo@primary:informix-> onstat -m

IBM Informix Dynamic Server Version 12.10.FC3 -- On-Line -- Up 00:11:59 -- 287724 Kbytes

Message Log File: /usr/informix/logs/castelo.log

[...]

14:16:29  Maximum server connections 1 
14:16:29  Checkpoint Statistics - Avg. Txn Block Time 0.000, # Txns blocked 0, Plog used 7, Llog used 2

14:16:34  Value of SESSION_LIMIT_LOCKS has been changed to 500.
14:16:39  Session SID=42 User UID=1002 NAME=informix PID=27743 has exceeded the session limit of 500 locks.

castelo@primary:informix->

Ótimo! O que poderíamos pedir mais?!
Continuando com os testes... Na referida apresentação é sugerido que podemos usar a instrução SET ENVIRONMENT... Portanto:

castelo@primary:informix-> dbaccess stores <<EOF
> SET ENVIRONMENT SESSION_LIMIT_LOCKS "1000";
> EOF

Database selected.


19840: Invalid session environment variable.
Error in line 1
Near character position 41


Database closed.

castelo@primary:informix->

Ouch... Não reconhece o nome da variável... Poderá ser uma das razões porque ainda não está documentado? Talvez... mas se pensarmos um pouco, as últimas variáveis de sessão que têm sido introduzidas, todas começam com o prefixo "IFX_" e depois têm o nome do parâmetro equivalente no ONCONFIG. Assim sendo, tentei isto:

castelo@primary:informix-> dbaccess stores <<EOF
> SET ENVIRONMENT IFX_SESSION_LIMIT_LOCKS "1000";
> EOF

Database selected.


Environment set.

Database closed.

castelo@primary:informix->


Boa! Depois adicionei isto ao caso de teste:

castelo@primary:informix-> cat test_locks_1000.sql
DROP TABLE IF EXISTS test_locks;

CREATE TABLE test_locks
(
        col1 INTEGER
) LOCK MODE ROW;

SET ENVIRONMENT IFX_SESSION_LIMIT_LOCKS "1000";
INSERT INTO test_locks
SELECT LEVEL FROM sysmaster:sysdual CONNECT BY lEVEL < 601;
castelo@primary:informix-> dbaccess stores test_locks_1000.sql

Database selected.


Table dropped.


Table created.


Environment set.


600 row(s) inserted.


Database closed.

castelo@primary:informix->


Bom, nada disto garante que funcione. Mas os testes acima tiveram o resultado esperado. Isto é o melhor exemplo da situação que descrevi no artigo já referido. Foram consumidos recursos para implementar isto, mas não está oficialmente disponível para os clientes, embora já tenho sido referido publicamente três vezes antes. Esperemos que isto seja documentado em breve. No meu entender esta é uma das funcionalidades mais desejadas pelos clientes. Refiro novamente que este seria um bom tópico de discussão na conferência de  utilizadores que se avizinha em Miami

Monday, March 24, 2014

Where is Informix? / Onde anda o Informix?

This article is written in English and Portuguese (original version here)
Este artigo está escrito em Inglês e Português (versão original aqui)


English version:

This is a very simple post just to echo an article from a friend and former colleague, Eric Vercelletto. I can say a couple of things about Eric. To start, he has a long history with Informix, has a lot of experience in IT in general, I learned quite a lot with him, he's fun, he was the original author of a script that I still maintain (to select among several Informix environments), although the site where it should be available is always down due to lack of time, and finally I can never write his last name without a typo! :)

All this to say it's a pleasure to see him active in the community. He recently created the website http://www.informix-swat.com to join Informix specialist and companies looking for them, has just recently introduced an RFE (Request For Enhancement) for an interesting subject (you got my comment on that one) and last but not least wrote a very interesting paper about the topic: Where is Informix?
In this document Eric talks about history and I do agree with most of it. I do have some remarks though:

  • The version launch dates are correct and show something that is impressive for a product that our competitors pretend that is dead: Since 2001 (13 years ago), we've released a major release with at most around two years interval. And during the life cycle of a version we keep a steady rate of fixpacks bringing updates, fixes and since a few years ago continuous innovation and new features.
    And as I wrote recently in a discussion on the IIUG mailing list, we're currently providing an N-2 support policy, meaning we support the current version (12.10 or "N"), the previous one (11.70 or "N-1") and the one before that (11.50 or "N-2"). I don't like the idea, but I'm sure many customers do
  • Eric says 11.50 was "small enhancements and adjustments". I wouldn't say so... It contained:
    • UPDATES on secondaries
    • SSL
    • Optimistic locking through the hidden version columns (introduced to facilitate updates on secondaries)
    • Dynamic SQL in SPL procedures
    • Data compression (in later fixpacks)
  • Eric says IBM had decided to incorporate Informix features in DB2. I think only a bunch of people really know what were the initial plans, the present plans, and the future plans. And as with all long term planning, it changes. The facts show that yes, there has been some technology interchange and I wouldn't expect anything different:
    • DB2 inherited the basic HDR concept (called HADR on DB2)
    • Informix inherited some UNICODE support
    • Informix got DRDA
    • Informix got compression (appeared first on DB2)
    • Informix and DB2 inherited in-memory technology from the "blink project" (implemented differently and first in Informix)
    • I believe Informix inherited encryption from DB2 (the same functions exist across DB2 product lines/platforms)
    • JSON exists on both (not necessarily with the same functionality)
  •  Eric says "It was also rumored that at this time some IBM sales persons would not hesitate to sell the ‘Red DBMS’ to Informix customers"
    Well... The magic of a rumor is that it can be rebated. But let's analyze this: IBM is a giant with several areas (software, hardware, business services, technical services, financing etc.). These areas try to maximize synergies to supply end to end solutions. But they also act "solo" on the market. The majority of the Unix/Linux market belongs to Oracle. Are you surprised that my hardware colleagues want to sell Power systems (AIX) to those customers? I'm not! Business services try to win deals in Oracle or MS SQL Server shops. Are you surprised they won't refuse to work with those products or even include them in their solutions if the customer has a preference?! I'm not.
    A completely different thing would be to imagine that a software sales person would "sell" Oracle. For start, it's impossible. And more important: A sales person follows the money. And they would get commissions on those impossible sales :)
But again, the paper is very interesting to read. And shows a clear image: The investment in the product is there. The fact that it's less known than it should, the fact that customers are loyal etc.
Well done!


Versão Portuguesa:

Este é um artigo muito simples, apenas para fazer eco de um artigo de um amigo e antigo colega, Eric Vercelletto. Para começar o Eric tem um longo historial com Informix, uma grande experiência em TI, aprendi bastante com ele, foi o autor original de um script que ainda mantenho (para selecionar entre ambientes Informix) apesar de o site onde deveria estar passar mais tempo em baixo que ligado, e finalmente nunca consigo escrever o seu apelido sem me enganar :)

Tudo isto para dizer que é um prazer vê-lo ativo na comunidade. Ainda recentemente criou um site (http://www.informix-swat.com) para juntar os especialistas Informix e empresas que andem à sua procura. registou um RFE (Request For Enhancement) sobre um tema interessante, e por último publicou um artigo sobre o tema: Onde está o Informix? (Where is Informix?)
No mesmo, o Eric fala sobre a história do Informix e concordo com a maioria do que escreve. Mas tenho alguns comentários:
  • As datas de lançamento das versões estão corretas e mostram algo que é impressionante sobre um produto que a concorrência faz de conta que morreu: Desde 2001 (há 13 anos atrás) temos lançado uma versão major com no máximo cerca de dois anos de intervalo. E durante o ciclo de vida de cada versão mantemos um ritmo previsível de fixpacks que trazem updates, correções  e de há uns anos para cá inovação continuada e novas funcionalidades.
    E como escrevi recentemente numa discussão na lista de correio do IIUG, atualmente está em vigor uma política de suporte "N-2" para o Informix, o que significa que suportamos a versão mais atual (12.10 ou "N"), a anterior (11.70 ou "N-1"), e a que precedeu esta (11.50 ou "N-2"). Pessoalmente não gosto da ideia, mas tenho a certeza que muitos clientes gostam
  • O Eric diz que a 11.50 foi "small enhancements and adjustments" (pequenas melhorias e ajustes). Não diria tanto.... Continha:
    • UPDATES nos secundários
    • SSL
    • Optimistic locking pelo uso de colunas de versão escondidas (introduzido para facilitar os updates nos secundários)
    • SQL dinâmico nos procedimentos SPL
    • Compressão de dados (em fixpacks posteriores)
  • O Eric diz que a IBM decidiu incorporar funcionalidades do Informix no DB2. Penso que apenas um punhado de pessoas sabiam realmente quais eram os planos iniciais, quais são os atuais ou quais serão os futuros. É que como qualquer planeamento de médio/longo prazo, as situações mudam. Os factos mostra efetivamente que houve transferência de tecnologia e não seria de esperar algo diferente:
    • O DB2 herdou a base do HDR (chamado HADR no DB2)
    • O Informix herdou o suporte a UNICODE
    • O Informix recebeu o  DRDA
    • O Informix recebeu a compressão (apareceu primeiro no DB2)
    • O Informix e o  DB2 herdaram a tecnologia de base de dados em memória do "projecto blink" (implementado primeiro no Informix e agora de forma diferente no DB2
    • Julgo que o Informix herdou a encriptação (colunas) do DB2 (as funções existem em várias plataformas do DB2)
    • O JSON existe em ambos (não necessariamente com as mesmas funcionalidades)
  • O Eric diz "It was also rumored that at this time some IBM sales persons would not hesitate to sell the ‘Red DBMS’ to Informix customers" ("existe também o rumor que os vendedores da IBM não hesitavam em vender a RDBMS vermelha a clientes Informix")
    Bom... a magia dos rumores é que não vale a pena rebatê-los. Mas vamos analisar isto: A IBM é um gigante com muitas áreas (software, hardware, serviços de negócio, serviços técnicos, financiamento etc.). Estas áreas tentam maximizar sinergias para fornecerem soluções completas. Mas também atuam "a solo" no mercado. A maioria do mercado Unix/Linux pertence à Oracle. Surpreende-o que os meus colegas de hardware queiram vender sistemas Power a esses clientes? A mim não! Os serviços de negócio ganham negócios em clientes Oracle e MS SQL Server. Surpreende-o que não se recusem a trabalhar com esses produtos ou mesmo incluí-los nas suas soluções se o cliente tiver uma preferência? A mim não!
    Algo completamente diferente seria imaginar que um vendedor de software tentasse vender Oracle. Para começar seria impossível. E mais importante: Um vendedor segue o dinheiro. E neste caso não receberiam nada por essas vendas impossíveis
Mas mais uma vez, o documento está interessante. E mostra uma imagem clara: O investimento no produto, o facto de que é menos conhecido que o que merecia, o facto de que os clientes são fiéis etc.
Muito bem!

Tuesday, March 18, 2014

Explain plans: for the last time / Planos de execução: pela última vez

This article is written in English and Portuguese (original version here)
Este artigo está escrito em Inglês e Português (versão original aqui)

English version:

If there is a topic that have always caught my attention it's the ability (or lack of) to capture a query plan in a client tool. This has been one of the most dirty Informix "secrets". This should be an essential feature of any RDBMs, and Informix provided the query plan, but in a very akward manner. A file was written on the database server (or on a filesystem mounted on the database server). This served us well enough when programmers used to work on the same machine as the database server, but those times are gone (a long time ago). I dedicated some time to a rather complex way of solving this after IBM introduced a function called EXPLAIN_SQL() that would return an XML file containing the query plan. This was the topic for my presentation on IIUG conference in 2010, but it was no more than a proof of concept. In other words it was not useable.
More recently I implemented a much simpler way to have the plan in any tool and documented it here in the blog. This works, it's simple and has little to no drawbacks. But it's still an hack...

Now, with some 20 years of delay, an article tells us that IBM has finally implemented this. There is a new function called ifx_explain() that accepts the query for which we want the query plan and returns the plan in text format. There is also an equivalent function called bson_explain() that returns the query plan in BSON format which can be casted to JSON (::JSON)

Please note that this is not documented. This new website (meanwhile it was added to the link list) is very recent and seems to be a great source of information. Some tweets mentioned it as belonging to John Miller who is one of the historic guys behind Informix (he was involved in all things related to backups, he's the "father" of Open Admin Tool, has several articles which even today are the references about update statistics, is deeply involved in JSON functionality etc.).

As a final note, I'd like to speak about something that is known to happen and this is just a clear example of that: we have implemented features in the engine which are not documented. The reason for that should be that they haven't passed (does not mean they failed or would fail) through the QA tests considered necessary to allow their general use. Which is understandable. But my point is that some of these were implemented too long ago. Time and resources were employed in creating them, and after too much time customers still haven't seen the benefits of that work. From my humble and personal (I must underline the "personal" for obvious reasons) perspective, there are some major issues with these situations:

  1. The cost (time and resources translate directly into money) it took to implement them are a waste until the day customers can use them and we can speak about them
  2. Some features (specifically SQL compatibility functions) may be used by customers without them knowing they're not documented. As an hypothetical example consider the new QUARTER() function announced in 12.10.xC3. A customer that is used to use that function in other RDBMs may just write it in SQL queries. If the server accepts it, he won't noticed if by any chance it was not (yet) documented. And if it's buggy, nasty things could happen, because in theory the customer was using a "non-existent" function, that was accepted by the server.
  3. Occasionally some of these functionalities are "leaked". I won't forget that I saw an ONCONFIG parameter in one of the sessions of IOD conference a few years ago, that was a very necessary feature for customers. I mentioned that to at least one customer and later I noticed it was not documented. After internal questioning the official position was "it didn't go through proper QA". Well... a bit late. Neither the slide had information that was supposed to be undocumented nor did I check that it was not documented. I simply tested and it worked!
So, my position about this is simple: If it's supposed to be used, it must be documented. If it's not supposed to be used, the engine MUST not accept it.  And in some cases I feel we're needing just a little bit more work (for QA) so that we can document those features and take "profit" (meaning allowing customers to use them) from all the investment put into it's creation.
Maybe the users and my colleagues that will be joining the IIUG 2014 conference in Miami want to include this topic in their discussions?

Having said this, it's a great day, as we closed a sad story about Informix!
If you're using 12.10.xC2+ then use this new feature. If not, try my soluction referenced above.

Versão Portuguesa:

Se há um assunto que sempre me mereceu atenção é a capacidade (ou falta dela) de capturar um plano de execução de uma query e apresentá-lo  numa ferramenta cliente. Este tem sido um dos "segredos sujos" do Informix. Isto será uma funcionalidade essencial a qualquer sistema de bases de dados, e de facto o Informix sempre disponibilizou o plano de execução, mas de uma maneira muito arcaica. O mesmo é escrito num ficheiro localizado (ou pelo menos acessível) no servidor de base de dados. Isto servia-nos razoalvelmente bem quando os programadores costumavam trabalhar na mesma máquina onde corria a base de dados. Mas esses tempos já lá vão (há muito tempo...).
Dediquei algum tempo a uma solução complexa para resolver isto, quando a IBM introduziu uma função chamada EXPLAIN_SQL() que devolvia a representação do query plan em XML. Este foi inclusive o tópico da minha apresentação na conferência de utilizadores do IIUG em 2010. Mas nunca passou de uma prova de conceito, ou por outras palavras nunca foi algo utilizável.
Mais recentemente implementei de forma muito mais simples a obtenção do plano de execução nas ferramentas cliente e documentei-o aqui no blog. Esta forma funciona e tem poucos ou nenhumas desvantagens. Mas ainda assim é um truque...

Porém agora, com uns vinte anos de atraso, apareceu um artigo que nos diz que a IBM finalmente implementou isto. Existe uma nova função chamada ifx_explain() que aceita a query para a qual queremos obter o plano de execução e retorna o mesmo sob a forma de texto simples. Existe ainda uma função semelhante, chamada bson_explain() que retorna o plano como um objecto BSON que pode ser transformando em JSON (::JSON)

Tenha em consideração que isto não está documentado. Este novo website (entretanto adicionado à lista de links) é muito recente e parece ser uma excelente fonte de informação. Alguns tweets mencionam que pertencerá ou que foi criado pelo John Miller, que é nem mais nem menos que um dos "históricos" por detrás do Informix (esteve envolvido com tudo o que se relaciona com backups, é o "pai" do Open Admin Tool, tem vários artigos que ainda hoje são as referências sobre o UPDATE STATISTICS, está profundamente envolvido com as funcionalidades JSON etc...)

Como nota final, gostaria de falar sobre algo que se sabe acontecer e este caso é um exemplo claro disso mesmo: temos implementado funcionalidades no motor que não se encontram documentadas. A razão para tal deverá ser que as mesmas não passaram (não necessariamente que falharam ou falhassem) pelos devidos testes de qualidade (QA), de forma a estarem prontas para uso genérico nos clientes. E isto parece-me razoável. Mas o meu "problema" é que algumas delas já foram implementadas há demasiado tempo. Tempo e recursos foram empregues para as criar, e mesmo depois de muito tempo os clientes ainda não podem tirar proveito desse esforço. Da minha humilde e pessoal (e é necessário reforçar o "pessoal" por motivos óbvios) perspectiva há vários potencias problemas que derivam destas situações:
  1. Os custos (tempo e recursos traduzem-se directamente em dinheiro) que derivaram da implementação destas funcionalidades são um desperdício até ao dia em que os clientes as possam usar e que possamos falar delas
  2. Algumas funcionalidades (especificamente funções de compatibilidade SQL) podem ser usadas pelos clientes, sei que eles saibam que não são documentadas. Como exemplo hipotético, consideremos a nova função QUARTER() introduzida na 12.10.xC3. Um cliente que esteja habituado a escrever SQL com essa função noutra base de dados, pode perfeitamente escrevê-la em Informix. Se o servidor a aceitar, o cliente não se irá aperceber se a função está ou não (ainda) documentada. E se a mesma estiver ainda imperfeita ou instável, coisas imprevisíveis podem acontecer, simplesmente porque um cliente usou algo "que não existe" mas que o servidor aceitou
  3. Ocasionalmente, algumas destas funcionalidades "transparecem" para a comunidade. Não me vou esquecer de ter visto um parâmetro de $ONCONFIG numa sessão de uma conferência IOD há alguns anos atrás, que ativa uma funcionalidade bastante necessária aos clientes. Eu já a mencionei a pelo menos um cliente e só depois me apercebi que não estava documentada. Depois de indagar internamente entendi que a posição oficial era "não sofreu testes significativos de QA". Bom... um pouco tarde demais. Nem o diapositivo tinha informação de que não estava documentado, nem eu verifiquei isso. Apenas fiz alguns testes e funcionou!
Portanto, a minha posição sobre o tema é simples: Se é suposto ser usado tem de estar documentado. Se não é suposto ser usado o motor NÃO pode aceitar. E em alguns casos sinto que necessitamos um pedacinho mais de esforço (para QA), de forma a que possamos documentar estas funcionalidades e obter "lucro" (ou seja, permitir que os clientes as usem) de todo o investimento colocado na sua criação.
Talvez os utilizadores e colegas que vão estar presentes na conferência do IIUG 2014 em Miami queiram incluir este tópico nas suas discussões?

Posto isto, foi um grande dia, pois fechámos uma história triste do Informix.
Se usa uma versão 12.10.xC2+ use esta nova funcionalidade. Senão recorra à forma que documentei e que referi no início

Informix 12.10.xC3

This article is written in English and Portuguese (original version here)
Este artigo está escrito em Inglês e Português (versão original aqui)

English version:

IBM has just released Informix 12.10.xC3 this last Friday (March 14). The packages were available on FixCentral since the beginning of the week, but the documentation was updated only on Friday. As usual for a few years each fixpack contains small improvements and a few gems. This one is no exception. Here is the list directly from the documentation with a few comments added:

  • Migration
    • Server changes
    • JSON compatibility pre- and post-migration requirements
    • New reversion requirements
      These are "just" some new parameters and things we should consider when upgrading or downgrading. I will refer to some of them later
  • Installation
    • Server configuration
      • Automatically configure the server during installation
        If we choose to configure a server during installation, resources are adjusted automatically and the JSON listener is started
  • Administration
    • Autonomics
      • Automatic resource tuning for performance
        Some of the new parameters mentioned above are relevant to this. As an example we can have a dynamic buffer pool, let the server create more logical logs, let it adjust the physical log size and reconfigure the CPU and AIO VPs. This is another great step in the autonomic chapter.
      • Automatic location and fragmentation
        Another major change. If you prefer (set AUTOLOCATE parameter) the new tables are automatically created in a set of dbspaces, and fragmented in round-robin. If the tables grow, new fragments are automatically created. No more "no more pages" errors. For the old timer DBA (like me) this sounds tricky... but times do change and we must keep up. You're not forced to use this, but it will probably fit some environments
  • Performance
    • Control the size of private memory caches
      In previous fixpacks the private memory caches used by each CPU VP changed to dynamic. Now you have the option to make them static
    • Virtual shared memory segment size doubling
      Like we do in the extents for the tables, each 16 memory segments that we allocate we double their size. The idea is to keep their number low. But again, for old timers, 16 is already a very large number. We usually try to keep them below 5 (?). But this also means we can have them lower initially because we know that if the server grows to much, it will adapt.
  • Connectivity
    • Retrying connections
      As we've seen in 11.70.xC8, we can now define INFORMIXCONTIME and INFORMIXCONRETRY as $ONCONFIG parameters and by using the SET ENVIRONMENT statement.
      This seems nice but to be honest I was not really getting it (I should have noticed it when I wrote about 11.70.xC8). My confusion is caused by the fact that I usually use these settings to avoid spending too much time trying to connect to a dead or unreachable server. But if we cannot reach the server how would having these settings on the server side help?!
      Because this is to be applied on distributed queries and for that it makes sense.
  • Application development
    • JSON compatibility
      • Use the MongoDB API to access relational data
        You can access relational tables with the MongoDB API methods
      • Improved JSON compatibility
        New MongoDB API methods are supported like findAndModify() and some authentication related operations
    • Foreign-key constraints
      • Temporarily prevent constraint validation
        As in 11.70.xC8 this introduces the ability to use NOVALIDATE on foreign-key constraints creation to speed up the process
      • Faster creation of foreign-key constraints
        As in 11.70.xC8, real creation of foreign keys can take better advantage of existing indexes
  • Compatibility
    • Find the quarter of the calendar year for dates
      Implementation of the QUARTER() SQL function. A request from the market for better integration with 3rd party BI tools
  • High-availability clusters and Enterprise Replication
    • Connection Manager
      • Improvements to Connection Manager
        Introduction of two new redirection policies: ROUNDROBIN and SECAPPLYBACKLOG
    • Monitoring
      • View log-staging information on RS secondary servers
        Get information about log staging information in RSS servers where the DELAY APPLY functionality is in use
    • Configuration
      • Easier configuration and cloning of a server for replication
        Easily configure and start Enterprise Replication
    • Sharding
      • Shard data across Enterprise Replication servers
        Shard is a term that refers to the distribution of a single object across a number of nodes. The purpose is a bit like "divide and conqueror". By distributing records, documents or rows we make them more manageable in each node and gain performance by having more hardware dealing with our data. Informix can now "shard" relational tables and collections (JSON) across instances in an Enterprise Replication domain
  • Spatial data
    • Enhancements for handling spatial data
      More spatial reference systems and the ability to calculate area and distance for data based on the round-Earth model.
      Informix spatial data types now conform to the OpenGIS Simple Features Specification for SQL Revision 1.1 and the ISO/IEC 13249-3 SQL/MM Part 3: Spatial. The Informix spatial solution is based on the ESRI SDE 10.2 Shape and PE libraries.
  • Time series data
    • Storage
      • Efficient storage for hertz and numeric time series data
        Timeseries can store a series of sub-second values in a packed element (up to 4KB)
    • Containers
      • Control the destroy behavior for rolling window containers
        Limit the number of windows of a rolling window container that can be destroyed in a single operation
      • Monitor groups of containers with wildcard characters
        Several monitorization functions now allow wildcards in the container name
  • Faster queries
    • Faster queries by running time series routines in parallel
      Functions that can be used in WHERE clause of a SELECT statement now can take advantage of PDQ PRIORITY (parallelism) if the tables are fragmented
    • Faster queries with IN conditions through virtual tables
      Optimization for queries with IN conditions
  • Warehousing
    • Additional types of data
      • Accelerate warehouse queries in-memory using data from multiple sources
        Synonyms and views can  now reference tables in different databases, tables in databases of the same Informix instance, or tables in a different Informix instance. This work for JSON data also

Beyond the very light review above, I'd like to highlight a few points:
  1. Dynamic buffer pool. Although currently it can "only" be set to self tune (it will grow within specified limits if the read cache hits are lower than a threshold we define), this will be an historical step. I remember that while explaining the dynamic parameters we were introducing, I sometimes mentioned that "some like BUFFERPOOL will possibly never be dynamic".... Well, I must rethink that statement. Although currently it's not dynamic, if it can automatically adjust the buffers, I imagine we'll be able to do the same in the future (by using onmode -wm/wf for example)
  2. You may noticed that some features introduced in xC3 of version 12.10 were already introduced in xC8 of version 11.70. This happens because some features are being developed across more than one code line, and they appear first in version N-1 or N depending on the release schedule and calendar. Nothing to do with marketing... If the code change is feasible in more than one version we give it to customers. We don't force them to upgrade to get any new stuff. How many vendors incorporate new features in previous product versions?!
  3.  Continuous improvements in many distinctive areas: Timeseries, JSON, IWA.




Versão Portuguesa:

A IBM acabou de lançar o fixpack 12.10.xC3 esta última sexta-feira (14 de Março). Os pacotes estavam disponíveis no FixCentral desde o inicio da semana, mas a documentação só foi atualizada na sexta-feira. Como é habitual desde há uns anos, cada fixpack contém algumas pequenas melhorias e algumas pérolas. Este não é exceção. Aqui está a lista diretamente da documentação com alguns comentários adicionados:
  • Migração
    • Mudanças no servidor
    • Compatibilidade com JSON: requisitos pré e pós-migração
    • Novos requisitos para regressões
      Existem alguns novos parâmetros e algumas ações a ter em conta quando se efetua um upgrade ou downgrade de versão. Irei mencionar alguns mais tarde
  • Instalação
    • Configuração do servidor
      • Configuração automática do servidor durante a instalação
        Se escolhermos configurar um servidor durante a instalação, os recursos são ajustados automaticamente e o serviço de JSON é iniciado
  • Administração
    • Autonomics
      • Ajuste de recursos automático para melhorar o desempenho
        Alguns dos parâmetros mencionados acima são relevantes para isto. Como exemplo podemos ter uma área de buffers dinâmica, deixar o servidor criar mais logical logs, alterar o physical log e reconfigurar os VPs do tipo CPU e AIO. È mais um passo significativo no capítulo da auto-gestão dos servidores
      • Fragmentação e alocação automática
        Mais uma mudança significativa. Se preferirmos (definindo o parâmetro AUTOLOCATE) as novas tabelas são espalhadas automaticamente por um conjunto de dbspaces e fragmentadas por round-robin. Se as tabelas crescerem, novos fragmentos serão automaticamente criados. Acabam-se os erros "no more pages". Para os DBAs "antigos" (como eu) isto parece suspeito... Mas os tempos mudam e temos de os acompanhar. Não somos obrigados a usar isto, mas sem dúvida que se ajusta a alguns ambientes.
  • Desempenho
    • Controlo sobre o tamanho das caches privadas
      Em fixpacks anteriores a memória privada alocada às caches de cada CPU VP passou a ser dinâmica. Agora existe a possibilidade de escolha e podemos defini-las com um tamanho estático também
    • Duplicação do tamanho dos segmentos virtuais
      Tal como fazemos nos extents das tabelas, a cada 16 segmentos que alocarmos o seu tamanho duplica. A ideia é manter o seu número "baixo". Mas mais uma vez, para os "antigos", 16 já é um valor demasiado alto. Normalmente tentamos manter o seu número abaixo de 5 (?). Mas apesar disso, isto significa que talvez possamos definir o seu tamanho muito mais pequeno ao início, pois sabemos que se o servidor crescer muito irá adaptar-se
  • Conectividade
    • Definição de tentativas de conexão
      Como vimos na 11.70.xC8, podemos agora definir as variáveis INFORMIXCONTIME e INFORMIXCONRETRY como parâmetros no $ONCONFIG e pela utilização da instrução SET ENVIRONMENT.
      Isto parece muito bem, mas para ser honesto, receio que não estava a compreender totalmente esta funcionalidade (e devia ter notado isto quando escrevi sobre a 11.70.xC8). A minha confusão foi causada pelo fato de que habitualmente uso estes parâmetros ou variáveis para evitar perder muito tempo a tentar ligações a um servidor que está em baixo ou não está acessível. Mas nesses casos, como é que ter estes parâmetros do lado do servidor ou numa sessão já estabelecida ajudariam?! Na verdade a ideia é aplicar isto a queries distribuídas e aí já faz todo o sentido
  • Desenvolvimento aplicacional
    • Compatibilidade com JSON
      • Usar a MongoDB API para aceder a dados relacionais
        Podemos aceder a tabelas relacionais (tradicionais) do Informix com os métodos da MongoDB API
      • Mais compatibilidade com  JSON
        Mais métodos da MongoDB API são agora suportados como o findAndModify() e alguns outros relacionados com autenticação
    • Chaves estrangeiras
      • Desabilitar temporariamente a validação das chaves estrangeiras
        Como na 11.70.xC8, isto introduz a possibilidade de usar a cláusula NOVALIDATE na criação de chaves estrangeiras
      • Criação mais rápida de chaves estrangeiras
        Tal como na 11.70.xC8, a criação de chaves estrangeiras (com validação) pode tirar mais proveito de índices já existentes
  • Compatibilidade
    • Obter o trimestre (quarter) de uma data
      Implementação da função SQL QUARTER(). Um pedido do mercado para integração com terceiros, fornecedores de ferramentas de BI
  • Clusters de alta-disponibilidade e Enterprise Replication
    • Connection Manager
      • Melhorias no Connection Manager
        Introdução de duas novas políticas de redirecionamento: ROUNDROBIN e SECAPPLUBACKLOG
    • Monitorização
      • Obter informação sobre log staging em servidores secundários remotos
        Em servidores onde o DELAY APPLY foi ativado é possível agora obter informação sobre os logs que vão sendo acumulados
    • Configuração
      • Facilidade na configuração de um servidor para Enterprise Replication
        A ferramenta de clonagem (ifxclone) facilita agora a ativação automática de Enterprise Replication
    • Sharding
      • Shard de dados entre servidores configurados em Enterprise Replication
        "Shard" é um termo que se refere à distribuição de um objeto pelos nós de um cluster de replicação. O objetivo é um pouco "dividir para reinar". Ao distribuir registos, documentos ou linhas torna-mo-los mais manejáveis em cada nó e ganhamos desempenho pois temos mais hardware para os gerir. O Informix pode agora fazer o shard de tabelas relacionais e collections JSON entre instâncias configuradas num domínio de Enterprise Replication
  • Dados espaciais
    • Melhorias no tratamento de dados espaciais
      Mais sistemas de referência e a possibilidade de calcular áreas e distâncias em dados baseados no modelo esférico da Terra.
      Os tipos de dados espaciais seguem agora a norma OpenGIS Simple Features Specification for SQL Revision 1.1 e a ISO/IEC 13249-3 SQL/MM Part 3: Spatial. A solução espacial Informix é baseada nas bibliotecas ESRI SDE 10.2 Shape e PE
  • Dados Timeseries
    • Armazenamento
      • Armazenamento eficiente para dados em séries numéricas e hertzianos
        Um elemento Timeseries compactado pode conter até 4KB de dados hertzianos (intervalos sub-segundo)
    • Containers
      • Controlo sobre o comportamento destrutivo de rolling window containersPodemos limitar o número de janelas que são destruídas numa só operação sobre um container em rolling window 
      • Monitorizar containers com caracteres wildcard
        Várias funções de monitorização passam a aceitar wildcards nos nomes dos Containers
  • Queries mais rápidas
    • Queries mais rápidas via execução paralela de rotinas
      As funções que podem ser usadas na cláusula WHERE das instruções SELECT podem ser executadas em paralelo (tirando proveito dos valores de PDQPRIORITY) se as tabelas estiverem fragmentadas
    • Queries mais rápidas nas condições IN sobre tabelas virtuais (VTI)
      Otimização de queries com IN
  • Warehousing
    • Tipos de dados adicionais
      • Aceleração de warehouse queries in-memory usando dados de múltiplas fontes
        Sinónimos e views usados para o IWA podem agora referencias tabelas em diferentes bases de dados, tabelas da mesma instância ou tabelas noutras instâncias. Dados JSON podem também ser usados

Para além da breve análise acima, gostaria de salientar alguns pontos:
  1. Buffer pool dinâmica. Apesar de atualmente "apenas" poder ser configurada para se auto-ajustar (crescerá se a percentagem de hits da cache de leitura ficar abaixo do limite por nós definido durante um intervalo de tempo), este será um passo histórico.
    Recordo-me de em várias ocasiões estar a explicar a transformação gradual dos parâmetros em dinâmicos (poderem ser mudados sem parar a instância), ter referido que "a BUFFERPOOL por exemplo possivelmente nunca será dinâmico". Parece que tenho de rever esta posição, ainda que de momento e no sentido estrito não o seja. Mas parece-me razoável pensar que no futuro poderemos mudar este parâmetro com um onmode -wm/-wf ou usando a SQL Admin API
  2. Poderá ter reparado que algumas das funcionalidades aqui descritas já tinham aparecido na 11.70.xC8. Isto acontece porque algumas mudanças de código podem ser transversais às versões, aparecendo na N-1 ou N conforme o ciclo normal de releases e o calendário. Nada que ver com marketing. Se a mudança de código é viável na versão N-1 nós fornece-mo-la aos clientes. Não obrigados a estar sempre na última versão se quiser beneficiar de algumas inovações. Quantos fornecedores incorporam funcionalidades novas em versões anteriores dos seus produtos?
  3. Melhorias contínuas em áreas que distinguem o Informix da concorrência: Timeseries, JSON e IWA.