jeudi 22 mars 2012

Je me suis mis à Python

Mais j'ai du m'arrêter après 3 lignes, parce que je me suis fait router sur une autre tâche. Ceci dit, en 3 lignes, j'ai découvert:

  • Qu'il existe un mode Emacs tout à fait remarquable, permettant notamment d'exécuter tout ou partie du buffer, un peu comme le mode Emacs d'OCaml

  • Qu'il existe une bibliothèque pour lire les fichiers CSV, simple et complète

  • Qu'il est trivial d'exécuter des commandes shell depuis le programme

  • Mais qu'il va quand même falloir que je m'habitue à ne rien avoir à déclarer

Bon début, donc.

jeudi 15 mars 2012

DB2 ou Sybase?

C'est le choix cornélien qui me tombe dessus au boulot.

D'un côté, DB2, que nous utilisons depuis fort longtemps, mais dont les performances sont plutôt mauvaises (rien à voir à priori avec le moteur en lui même, c'est plutôt une histoire de performances du stockage réseau), à tel point que nous avons peut-être aujourd'hui perdu un important client, excédé de nos problèmes de performances. Ajoutons également que les DBAs nous facturent en interne une petite fortune, et l'on comprend pourquoi l'on songe à bouger.

De l'autre, Sybase, qui a l'énorme avantage de coûter quelque chose comme 20 fois moins au bas mot, grâce à la ristourne négociée par le département en échange d'un achat massif de licenses. Les performances pourraient être meilleures (?), mais les fonctionnalités semblent moins à la hauteur. L'absence de requêtes récursives est un problème qui pourrait être particulièrement difficile à émuler, et complexifier de fait la couche applicative. L'exécution de requêtes concurrentes pourrait être moins efficace. Et enfin, je n'ai toujours pas réussi à faire fonctionner leur bibliothèque ODBC en 64 bits.

Je n'aurais pas eu d'hésitations à proposer Postgresql, mais malheureusement ce n'est pas une option dans notre monde merveilleux. Tant pis, on fera avec.

samedi 10 mars 2012

Aller chercher la classe de base

Un test de C++, plutôt moyen au demeurant, m'a permis de découvrir une syntaxe pour appeler la fonction de base sur un type dérivé:


#include

class Base
{
public:
virtual ~Base() {}
virtual void f() { std::cout << "Base" << std::endl; }
};

class Derived : public Base
{
public:
virtual void f() { std::cout << "Derived" << std::endl; }
};

int main()
{
Derived d;
d.Base::f();
}

Au final, cette syntaxe est plutôt logique: depuis une méthode dérivée, on peut en effet appeler une méthode de base avec Base::f(), c'est à dire this->Base::f(). Donc, pourquoi pas sur un autre objet que this?

Badge tumbleweed

La plupart de mes questions de programmation ont déjà leur réponse sur StackOverflow, mais il arrive parfois que sur un sujet suffisamment précis, je me lance à poster.

Le résultat n'est pas tout à fait à la hauteur de mes attentes, mais j'en récupère cependant un avantage: je suis maintenant le détenteur du badge Tumbleweed, qui récompense les questions n'ayant reçu ni réponses, ni commentaires, ni votes pendant une semaine.

jeudi 1 mars 2012

Analysez vos tables

D'abord, créons une table raisonnablement grosse, avec un bel index créé implicitement par la clé primaire.


drop table if exists numbers;
create table numbers(n integer primary key);
insert into numbers select generate_series(1, 100000);

Si l'on veut chercher une valeur en particulier, l'on voit que le planificateur de tâches décide très raisonnablement de passer par l'index:

select * from numbers where n = 1297



Là où ça devient intéressant, c'est lorsque l'on passe par une table temporaire, parce que l'on peut vouloir chercher par exemple plusieurs valeurs à la fois:

create temporary table test(n integer not null);
insert into test values(1297);

Regardons le plan...

select * from numbers n join test t on n.n = t.n;

Stupeur, le planificateur décide de hacher l'ensemble de la table "numbers", au lieu d'utiliser l'index.


En effet: le planificateur, ne connaissant pas la taille de la table temporaire, suppose par défaut qu'elle fait 1000 lignes, et par conséquent choisit un plan non optimal.

Heureusement, il est possible de lui demander d'analyser la table afin de mettre à jour ses statistiques.

Ansi:

analyze test;
select * from numbers n join test t on n.n = t.n;

nous donne enfin le plan recherché.


L'on peut ainsi dépenser quelques millisecondes au sein de la transaction pour mettre à jour ses statistiques, et sauver ainsi potentiellement plusieurs secondes en permettant au planificateur de mieux choisir.