memcached インタフェースを使用するために既存の MySQL スキーマまたはアプリケーションを改変する場合、memcached アプリケーションの次の点を検討してください。
スペースまたは改行文字は ASCII プロトコルで区切り文字として使用されるため、memcached のキーにこれらの文字を含めることはできません。スペースを含む検索値を使用する場合は、
add()
、set()
、get()
などの呼び出しでこれらをキーとして使用する前に、スペースのない値に変換またはハッシュします。これらの文字は、理論上、バイナリプロトコルを使用するプログラム内でキーとして許可されますが、さまざまなクライアントとの互換性を確保するために、キーに使用される文字を常に制限します。-
InnoDB
テーブルに短い数値の主キーカラムがある場合、整数を文字列値に変換すると、memcached の一意の検索キーとして使用できます。memcached サーバーが複数のアプリケーションで使用される場合、または複数のInnoDB
テーブルとともに使用される場合、一意性を保つために名前の変更を検討してください。たとえば、数値の前にテーブル名やデータベース名とテーブル名を付けます。注記MySQL 5.6.14 以降では、
InnoDB
memcached プラグインは、主キーとしてINTEGER
が定義されたマップ済みInnoDB
テーブル上での挿入および読み取りをサポートします。 memcached インタフェースからクエリーを実行したり格納したりしたデータについて、パーティション化されたテーブルは使用できません。
-
memcached プロトコルは数値を文字列として渡します。ベースとなる
InnoDB
テーブルに数値を格納する場合、たとえば、SUM()
やAVG()
などの SQL 関数に使用できるカウンタを実装するには、次のようにします。予想される最大数のすべての桁 (さらに該当する場合はマイナス符号、小数点またはその両方に対する追加の文字) を保持するために十分な文字がある
VARCHAR
カラムを使用します。-
カラム値を使用して計算を実行するすべてのクエリー内で、
CAST()
関数を使用して、文字列から整数またはその他の数値型に変換します。例:-- Alphabetic entries are returned as zero. select cast(c2 as unsigned integer) from demo_test; -- Since there could be numeric values of 0, can't disqualify them. -- Test the string values to find the ones that are integers, and average only those. select avg(cast(c2 as unsigned integer)) from demo_test where c2 between '0' and '9999999999'; -- Views let you hide the complexity of queries. The results are already converted; -- no need to repeat conversion functions and WHERE clauses each time. create view numbers as select c1 key, cast(c2 as unsigned integer) val from demo_test where c2 between '0' and '9999999999'; select sum(val) from numbers;
結果セット内のアルファベットの値は、
CAST()
の呼び出しによって 0 に変換されます。結果セット内の行数に依存するAVG()
などの関数を使用する場合、数値以外の値を取り除くためのWHERE
句を含めるようにします。
キーとして使用する
InnoDB
カラムが 250 バイトよりも長くなる可能性がある場合、250 バイト未満の値になるようにハッシュします。-
memcached インタフェースで既存のテーブルを使用するには、そのテーブルのためのエントリを
innodb_memcache.containers
テーブル内に定義します。memcached を介して中継されるリクエストでテーブルをデフォルトに指定する場合、name
カラムに値default
を指定し、その後 MySQL Server を再起動して変更を有効にします。異なる種類の memcached データに対して複数のテーブルを使用している場合、ユーザーの選択したname
値を使用してinnodb_memcache.containers
テーブル内に複数のエントリをセットアップし、次にアプリケーション内でget @@
またはname
set @@
の形式で memcached リクエストを発行し、memcached API を経由する後続のリクエストについて使用されるテーブルを切り換えます。name
事前定義された
test.demo_test
テーブル以外のテーブルを使用する例については、例14.23「InnoDB + memcached アプリケーションのためのテーブルおよびカラムマッピングの指定」を参照してください。そのようなテーブルの必要なレイアウトとカラムの意味については、セクション14.18.7「InnoDB memcached プラグインの内部構造」を参照してください。 -
memcached のキー/値のペアによって複数の MySQL カラム値を使用するには、MySQL テーブルに関連付けられた
innodb_memcache.containers
エントリ内で、value_columns
フィールドに、カンマ、セミコロン、スペース、またはパイプ文字で区切られた複数のカラム名を指定します。たとえば、col1,col2,col3
またはcol1|col2|col3
のようになります。カラム値を、パイプ文字を区切り文字として使用した単一文字列になるように連結したあとで、その文字列を memcached の
add
またはset
呼び出しに渡します。文字列はさまざまなカラムに自動的にアンパックされます。個々のget
呼び出しは、やはりパイプ区切り文字によって区切られている複数のカラム値を含む単一文字列を返します。アプリケーション言語に応じた適切な構文を使用して、これらの値をアンパックします。
例 14.23 InnoDB + memcached アプリケーションのためのテーブルおよびカラムマッピングの指定
ここで、データ操作のために InnoDB
memcached プラグインを使用する MySQL アプリケーションのためにユーザー独自のデータを使用する方法の例を示します。
最初に、一部の国別データを保持するテーブルをセットアップします。データは、人口、メートル法で示した面積、右または左のどちら側を運転するかを示す 'R'
または 'L'
です。
use test;
CREATE TABLE `multicol` (
`country` varchar(128) NOT NULL DEFAULT '',
`population` varchar(10) DEFAULT NULL,
`area_sq_km` varchar(9) DEFAULT NULL,
`drive_side` varchar(1) DEFAULT NULL,
`c3` int(11) DEFAULT NULL,
`c4` bigint(20) unsigned DEFAULT NULL,
`c5` int(11) DEFAULT NULL,
PRIMARY KEY (`country`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ここで、InnoDB
memcached プラグインがこのテーブルにアクセスする方法を認識するように、このテーブルのディスクリプタを作成します。
CONTAINERS
テーブル内のサンプルエントリは、name
カラムが'aaa'
で、別の識別子'bbb'
をセットアップします。使用するすべての memcached アプリケーションに対して単一のマスターテーブルを作成した場合、ID を'default'
にして、テーブルを切り換えるための@@
リクエストをスキップします。test.multicol
テーブルを指定します。スキーマ名は 1 つのカラムに格納され、テーブル名は別のカラムに格納されます。キーカラムは一意の
country
値です。このカラムは上記のテーブルを作成するときに主キーに指定されたため、ここでインデックス名'PRIMARY'
も指定します。1 つの複合データを単一カラムに保持する代わりにデータを 3 つのテーブルカラムに分割するため、値を格納または取得するときに使用されるカラムのカンマ区切りリストを指定します。
さらに、フラグ、期限切れ、および CAS 値については、サンプルテーブル
demo.test
の設定に基づく対応するカラムを指定します。これらの値は、InnoDB
memcached プラグインを使用するアプリケーションでは通常はあまり重要ではありません。MySQL がデータの同期を保持するため、データが期限切れになったり古くなったりすることを心配する必要がないためです。
insert into innodb_memcache.containers
(name,db_schema,db_table,key_columns,value_columns,flags,cas_column,
expire_time_column,unique_idx_name_on_key)
values
('bbb','test','multicol','country','population,area_sq_km,drive_side',
'c3','c4','c5','PRIMARY');
commit;
ここで、プログラムからこのテーブルにアクセスする方法を示すサンプル Python プログラムを示します。
すべてのデータ操作は memcached インタフェースを介して実行されるため、データベース許可は不要です。知る必要があるのは、memcached デーモンがローカルシステム上でリスニングするポート番号のみです。
任意のいくつかの国のサンプル値をロードします。(ウィキペディアからの面積および人口の数値。)
プログラムで
multicol
テーブルを使用するために、@@
表記を使用してダミーのGET
またはSET
リクエストを行うswitch_table()
関数を呼び出します。リクエスト内の名前はbbb
で、これはinnodb_memcache.containers.name
に格納されている値です。(実際のアプリケーションでは、さらに記述的な名前を使用します。この例では、GET @@...
リクエストでテーブル名でなくテーブル識別子を指定することを示しています。データを挿入してクエリーを実行するためのユーティリティー関数は、
ADD
またはSET
リクエストによって MySQL に送信するために Python データ構造をパイプ区切り値に変換し、GET
リクエストによって返されるパイプ区切り値をアンパックするための方法を示します。この特別な処理は、単一の memcached 値を複数の MySQL テーブルカラムにマッピングする場合にのみ必要です。
import sys, os
import memcache
def connect_to_memcached():
memc = memcache.Client(['127.0.0.1:11211'], debug=0);
print "Connected to memcached."
return memc
def banner(message):
print
print "=" * len(message)
print message
print "=" * len(message)
country_data = [
("Canada","34820000","9984670","R"),
("USA","314242000","9826675","R"),
("Ireland","6399152","84421","L"),
("UK","62262000","243610","L"),
("Mexico","113910608","1972550","R"),
("Denmark","5543453","43094","R"),
("Norway","5002942","385252","R"),
("UAE","8264070","83600","R"),
("India","1210193422","3287263","L"),
("China","1347350000","9640821","R"),
]
def switch_table(memc,table):
key = "@@" + table
print "Switching default table to '" + table + "' by issuing GET for '" + key + "'."
result = memc.get(key)
def insert_country_data(memc):
banner("Inserting initial data via memcached interface")
for item in country_data:
country = item[0]
population = item[1]
area = item[2]
drive_side = item[3]
key = country
value = "|".join([population,area,drive_side])
print "Key = " + key
print "Value = " + value
if memc.add(key,value):
print "Added new key, value pair."
else:
print "Updating value for existing key."
memc.set(key,value)
def query_country_data(memc):
banner("Retrieving data for all keys (country names)")
for item in country_data:
key = item[0]
result = memc.get(key)
print "Here is the result retrieved from the database for key " + key + ":"
print result
(m_population, m_area, m_drive_side) = result.split("|")
print "Unpacked population value: " + m_population
print "Unpacked area value : " + m_area
print "Unpacked drive side value: " + m_drive_side
if __name__ == '__main__':
memc = connect_to_memcached()
switch_table(memc,"bbb")
insert_country_data(memc)
query_country_data(memc)
sys.exit(0)
ここに示すいくつかの SQL クエリーは、スクリプトが実行されたあとの MySQL データの状態を示し、SQL を介して同じデータに直接アクセスしたり、適切な MySQL コネクタまたは API を使用する任意の言語で記述されたアプリケーションからアクセスしたりする方法を示します。
テーブルディスクリプタ 'bbb'
があるため、memcached リクエスト GET @bbb
を発行すると、multicol
テーブルに切り換えることができます。
mysql: use innodb_memcache;
Database changed
mysql: select * from containers;
+------+-----------+-----------+-------------+----------------------------------+-------+------------+--------------------+------------------------+
| name | db_schema | db_table | key_columns | value_columns | flags | cas_column | expire_time_column | unique_idx_name_on_key |
+------+-----------+-----------+-------------+----------------------------------+-------+------------+--------------------+------------------------+
| aaa | test | demo_test | c1 | c2 | c3 | c4 | c5 | PRIMARY |
| bbb | test | multicol | country | population,area_sq_km,drive_side | c3 | c4 | c5 | PRIMARY |
+------+-----------+-----------+-------------+----------------------------------+-------+------------+--------------------+------------------------+
2 rows in set (0.01 sec)
スクリプトを実行したあと、データは multicol
テーブル内にあり、従来の MySQL クエリーまたは DML ステートメントから入手できます。
mysql: use test;
Database changed
mysql: select * from multicol;
+---------+------------+------------+------------+------+------+------+
| country | population | area_sq_km | drive_side | c3 | c4 | c5 |
+---------+------------+------------+------------+------+------+------+
| Canada | 34820000 | 9984670 | R | 0 | 11 | 0 |
| China | 1347350000 | 9640821 | R | 0 | 20 | 0 |
| Denmark | 5543453 | 43094 | R | 0 | 16 | 0 |
| India | 1210193422 | 3287263 | L | 0 | 19 | 0 |
| Ireland | 6399152 | 84421 | L | 0 | 13 | 0 |
| Mexico | 113910608 | 1972550 | R | 0 | 15 | 0 |
| Norway | 5002942 | 385252 | R | 0 | 17 | 0 |
| UAE | 8264070 | 83600 | R | 0 | 18 | 0 |
| UK | 62262000 | 243610 | L | 0 | 14 | 0 |
| USA | 314242000 | 9826675 | R | 0 | 12 | 0 |
+---------+------------+------------+------------+------+------+------+
10 rows in set (0.00 sec)
mysql: desc multicol;
+------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+-------+
| country | varchar(128) | NO | PRI | | |
| population | varchar(10) | YES | | NULL | |
| area_sq_km | varchar(9) | YES | | NULL | |
| drive_side | varchar(1) | YES | | NULL | |
| c3 | int(11) | YES | | NULL | |
| c4 | bigint(20) unsigned | YES | | NULL | |
| c5 | int(11) | YES | | NULL | |
+------------+---------------------+------+-----+---------+-------+
7 rows in set (0.01 sec)
数値として扱われるカラムの長さを定義する場合、必要な桁、小数点、符号文字、先行ゼロなどを保持する十分なサイズを考慮します。VARCHAR
などの文字列カラム内で値が長すぎると、その値は一部の文字を削除して切り捨てられ、不適切な数値が生成されることがあります。
SQL クエリーを使用して、country
キーカラムだけでなく任意のカラムを使用して計算およびテストを行うと、レポートを作成できます。(これらの例では少数の国のデータのみが使用されているため、数値は例示のみを目的としています。)ここで、右側を運転する国の平均人口と、名前が「U」で始まる国の平均面積を求めます。
mysql: select avg(population) from multicol where drive_side = 'R';
+-------------------+
| avg(population) |
+-------------------+
| 261304724.7142857 |
+-------------------+
1 row in set (0.00 sec)
mysql: select sum(area_sq_km) from multicol where country like 'U%';
+-----------------+
| sum(area_sq_km) |
+-----------------+
| 10153885 |
+-----------------+
1 row in set (0.00 sec)
population
および area_sq_km
カラムは厳密に型指定された数値データでなく文字データを格納するため、avg()
や sum()
などの関数は、最初にそれぞれの値を数値に変換します。この手法は <
や >
などの演算子では機能せず、 たとえば、文字ベースの値を比較するとき、9 > 1000
となり、これは ORDER BY population DESC
などの句で予期される結果ではありません。もっとも正確な型処理を行うには、数値カラムを適切な型にキャストするビューに対してクエリーを実行します。この技法では、非常に単純な SELECT *
クエリーをデータベースアプリケーションから発行でき、キャスト、フィルタ、および並べ替えがすべて正しくなります。ここで、人口の上位 3 か国を降順で求めるためにクエリーを実行するビューを作成します。結果は常に multicol
テーブルからの最新データを反映し、人口と面積は常に数値として扱われます。
mysql: create view populous_countries as
select
country,
cast(population as unsigned integer) population,
cast(area_sq_km as unsigned integer) area_sq_km,
drive_side from multicol
order by cast(population as unsigned integer) desc
limit 3;
Query OK, 0 rows affected (0.01 sec)
mysql: select * from populous_countries;
+---------+------------+------------+------------+
| country | population | area_sq_km | drive_side |
+---------+------------+------------+------------+
| China | 1347350000 | 9640821 | R |
| India | 1210193422 | 3287263 | L |
| USA | 314242000 | 9826675 | R |
+---------+------------+------------+------------+
3 rows in set (0.00 sec)
mysql: desc populous_countries;
+------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+-------+
| country | varchar(128) | NO | | | |
| population | bigint(10) unsigned | YES | | NULL | |
| area_sq_km | int(9) unsigned | YES | | NULL | |
| drive_side | varchar(1) | YES | | NULL | |
+------------+---------------------+------+-----+---------+-------+
4 rows in set (0.02 sec)