インデックスが対象とするカラムの名前を調べる

はいはい、お次はこれ。

まーにょ!

      uint nkey_parts = key.key_parts;
      KEY_PART_INFO key_part;
      int j = 0;
      for (; j < nkey_parts; j++) {
        key_part = key.key_part[j];
        uint16 fieldnr = key_part.fieldnr;
        Field *field;
        field = table->field[fieldnr-1];
        const char *field_name = field->field_name;
        printf("indexed field's name is %s\n", field_name);
      }

できた。KEY_PART_INFO.fieldnrは0スタートではなく1スタートなので、配列インデックスとして使う場合には-1する必要あり。

CREATE TABLE `t1` (
  `c1` int(11) NOT NULL,
  `c2` int(11) default NULL,
  `c3` int(11) default NULL,
  PRIMARY KEY  (`c1`),
  UNIQUE KEY `idx1` USING HASH (`c2`),
  KEY `idx2` (`c2`,`c3`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

こんなテーブルの場合、、

table alias is t1
number 0 key's type is BTREE
name = PRIMARY, key_length = 4, key_parts = 1, algorithm = 0
indexed field's name is c1
number 1 key's type is BTREE
name = idx1, key_length = 5, key_parts = 1, algorithm = 3
indexed field's name is c2
number 2 key's type is BTREE
name = idx2, key_length = 10, key_parts = 2, algorithm = 0
indexed field's name is c2
indexed field's name is c3

こんな感じで情報がとれます。

!!そう、気づいてしまったんですが、ha_myisam::index_typeが、algorithm=3のときに"BTREE"って返してます!!

ここはHASHって返して欲しい所。

覗いてみると、、、

const char *ha_myisam::index_type(uint key_number)
{
  return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
          "FULLTEXT" :
          (table->key_info[key_number].flags & HA_SPATIAL) ?
          "SPATIAL" :
          (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
          "RTREE" :
          "BTREE");
}

HASHが華麗にスルーされてますなw

あれ?MyISAMってHASH型インデックスはサポートしてなかったんだっけ? SHOW INDEXしてもBTREEと表示されるわけだが、そういう仕様だっけ?

http://dev.mysql.com/doc/refman/5.0/en/create-index.html

そういう仕様だったw frmファイルは"ALTER TABLE"を考慮しているので、SHOW CREATEだとHASHって出るのね。

インデックスの型を調べる

テーブルオブジェクトを取得できて、付与されているインデックスの数も分かったら次はこれ。

既に1個前のエントリで触れているように、handler::index_typeを使う。table->fileがhandlerへのポインタ。

    table = open_table(thd, table_list, thd->mem_root, 0, 0);
    printf("table alias is %s\n", table->alias);

    uint nkeys = table->s->keys;
    int i = 0;
    for (; i < nkeys; i++) {
      const char* tkey;
      tkey = table->file->index_type(i);
      printf("number %d key's type is %s\n", i, tkey);
    }

ちゃんと取れました。

table alias is t2
number 0 key's type is BTREE
number 1 key's type is BTREE
number 2 key's type is BTREE



で、実はもう1個方法がある。

KEYオブジェクトに触れれば、、、

typedef struct st_key {
  uint  key_length;                     /* Tot length of key */
  uint  flags;                          /* dupp key and pack flags */
  uint  key_parts;                      /* How many key_parts */
  uint  extra_length;
  uint  usable_key_parts;               /* Should normally be = key_parts */
  enum  ha_key_alg algorithm;
  KEY_PART_INFO *key_part;
  char  *name;                          /* Name of key */
  ...
} KEY;

名前とか、キーを構成するカラム数とか、インデックスの型(enum ha_key_alg)とか取れる。

しかしTABLEオブジェクトにあるKEYオブジェクトへのポインタって、プライマリキーだけっぽいんだよなぁ・・・。全キーへのポインタが取れればこっちのほうがいいのだけれども。



いくつかの既存のソースを見たら、table->key_infoってKEYオブジェクトへの配列へのポインタだったw

普通に行ける。

    printf("table alias is %s\n", table->alias);

    uint nkeys = table->s->keys;
    int i = 0;
    for (; i < nkeys; i++) {
      const char* tkey;
      tkey = table->file->index_type(i);
      printf("number %d key's type is %s\n", i, tkey);

      KEY key;
      key = table->key_info[i];
      printf("name = %s, key_length = %d, key_parts = %d, algorithm = %d\n",
             key.name, key.key_length, key.key_parts, key.algorithm);
    }

handler APIを使う必要無し。

table alias is t2
number 0 key's type is BTREE
name = PRIMARY, key_length = 4, key_parts = 1, algorithm = 0
number 1 key's type is BTREE
name = idx2, key_length = 5, key_parts = 1, algorithm = 0
number 2 key's type is BTREE
name = idx3, key_length = 10, key_parts = 2, algorithm = 0

補足: KEY.algorithmはenum ha_key_alg型。

enum ha_key_alg {
  HA_KEY_ALG_UNDEF=     0,              /* Not specified (old file) */
  HA_KEY_ALG_BTREE=     1,              /* B-tree, default one          */
  HA_KEY_ALG_RTREE=     2,              /* R-tree, for spatial searches */
  HA_KEY_ALG_HASH=      3,              /* HASH keys (HEAP tables) */
  HA_KEY_ALG_FULLTEXT=  4               /* FULLTEXT (MyISAM tables) */
};

0を返してきているということは、old file???

テーブルに付与されているインデックスの数を調べる

次はこれを知りたいのです。以下のようなhandler::index_type関数があるのですが、ここで投げるkey_numberを調べるには、というお話。

const char *index_type(uint key_number);

とりあえずTABLEオブジェクトを取得したら、以下を辿ってget。

uint nkeys = table->s->keys

sはTABLE_SHARE型のポインタ。名前から推測するに、frmファイルのオブジェクトなのではと思ふ。一つのテーブルに対してTABLEオブジェクトはmysqldプロセス内で複数生成されうるが、TABLE_SHAREは各テーブルにつき1つ、みたいな使い方なのではと、妄想。

補足:keysでは、複合キーの場合も1ずつカウントしています。インデックスが張られている延べカラム数は、key_partsに格納されているようです。

Enterprise Server 5.0.30リリース

MySQL Enterprise Server 5.0.30がリリースされたようです。Enterprise Serverは旧"MySQL Network"の購入者のみが利用できるバイナリだと思いますが(ダウンロードにログインが必要)、ログインできる方は以下から落とすことができます。

https://enterprise.mysql.com/software/enterprise.php

今回の目玉は、何といってもCPUスケーラビリティ向上パッチが入ったということではないでしょうか。近いうちにMySQL Community Server 5.0.29とかがリリースされて、GPLユーザの方も使えるようになるのではと思いますが。