14.21.5.1 为 InnoDB memcached 插件调整现有的 MySQL 模式
在调整现有的 MySQL 模式或应用程序以使用daemon_memcached
插件时,请考虑 memcached 应用程序的这些方面:
-
memcached 键不能包含空格或换行符,因为这些字符在 ASCII 协议中用作分隔符。如果您正在使用包含空格的查找值,请在将它们用作调用
add()
,set()
,get()
等的键之前,将其转换或散列为不包含空格的值。尽管从理论上讲,使用二进制协议的程序的键中允许使用这些字符,但是您应限制键中使用的字符,以确保与广泛的 Client 端兼容。 -
如果
InnoDB
table 中的数字primary key列较短,则可以通过将整数转换为字符串值,将其用作 memcached 的唯一查找键。如果 memcached 服务器用于多个应用程序,或者具有多个InnoDB
table,请考虑修改名称以确保其唯一性。例如,将 table 名或数据库名和 table 名放在数字值之前。
Note
daemon_memcached
插件支持在已将INTEGER
定义为主键的 Map 的InnoDB
table 上进行插入和读取。
-
您不能将分区 table 用于使用 memcached 查询或存储的数据。
-
memcached 协议将数字值作为字符串传递。要将数值存储在基础
InnoDB
table 中,以实现可在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;
Note
通过调用CAST()
,结果集中的所有字母值都将转换为 0.当使用诸如AVG()
之类的函数时,该函数取决于结果集中的行数,请包含WHERE
子句以过滤掉非数字值。
-
如果用作键的
InnoDB
列的值可能超过 250 个字节,则将值散列到小于 250 个字节。 -
要将现有 table 与
daemon_memcached
插件一起使用,请在innodb_memcache.containers
table 中为其定义一个条目。要使该 table 成为所有 memcached 请求的默认 table,请在name
列中指定值default
,然后重新启动 MySQL 服务器以使更改生效。如果您对不同类别的 memcached 数据使用多个 table,请在innodb_memcache.containers
table 中使用您选择的name
值设置多个条目,然后在应用程序中以get @@name
或set @@name
的形式发出 memcached 请求指定用于后续 memcached 请求的 table。
有关使用除 sched 义的test.demo_test
table 以外的 table 的示例,请参见示例 14.13“将自己的 table 与 InnoDB memcached 应用程序一起使用”。有关所需的 table 格布局,请参见第 14.21.7 节“ InnoDB memcached 插件内部”。
- 要将多个
InnoDB
table 列值与 memcached 键值对一起使用,请在InnoDB
table 的innodb_memcache.containers
条目的value_columns
字段中指定用逗号,分号,空格或竖线字符分隔的列名。例如,在value_columns
字段中指定col1,col2,col3
或col1|col2|col3
。
在将字符串传递给 memcached add
或set
调用之前,使用管道字符作为分隔符将列值连接为单个字符串。该字符串将自动解压缩到正确的列中。每个get
调用都返回一个包含列值的单个字符串,该列值也由竖线字符分隔。您可以使用适当的应用程序语言语法来解压缩值。
例 14.13 将自己的 table 与 InnoDB 内存缓存应用程序一起使用
此示例说明如何将自己的 table 与使用memcached
进行数据操作的示例 Python 应用程序一起使用。
该示例假定按照第 14.21.3 节“设置 InnoDB memcached 插件”的说明安装了daemon_memcached
插件。它还假定您的系统配置为运行使用python-memcache
模块的 Python 脚本。
- 创建
multicol
table,该 table 存储国家信息,包括人口,面积和驾驶员身侧数据('R'
代 table 右侧,'L'
代 table 左侧)。
mysql> USE test;
mysql> 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_memcache.containers
table 中,以便daemon_memcached
插件可以访问multicol
table。
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');
mysql> COMMIT;
multicol
table 的innodb_memcache.containers
记录指定name
值'bbb'
,这是 table 标识符。
Note
如果将一个InnoDB
table 用于所有 memcached 应用程序,则可以将name
值设置为default
,以避免使用@@
table 示法切换 table。
-
db_schema
列设置为test
,这是multicol
table 所在的数据库的名称。 -
db_table
列设置为multicol
,这是InnoDB
table 的名称。 -
key_columns
设置为唯一的country
列。country
列被定义为multicol
table 定义中的主键。 -
数据不是由一个
InnoDB
table 列来保存复合数据值,而是在三个 table 列(population
,area_sq_km
和drive_side
)之间划分数据。为了容纳多个值列,在value_columns
字段中指定了以逗号分隔的列列 table。value_columns
字段中定义的列是存储或检索值时使用的列。 -
flags
,expire_time
和cas_column
字段的值基于demo.test
samplestable 中使用的值。在使用daemon_memcached
插件的应用程序中,这些字段通常并不重要,因为 MySQL 使数据保持同步,并且无需担心数据过期或过时。 -
unique_idx_name_on_key
字段设置为PRIMARY
,它 table 示在multicol
table 的唯一country
列上定义的主索引。 -
将 samplesPython 应用程序复制到文件中。在此示例中,示例脚本被复制到名为
multicol.py
的文件中。
示例 Python 应用程序将数据插入multicol
table 中,并检索所有键的数据,演示了如何通过daemon_memcached
插件访问InnoDB
table。
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)
示例 Python 应用程序说明:
-
由于通过 memcached 接口执行数据操作,因此无需数据库授权即可运行该应用程序。唯一需要的信息是 memcached 守护程序侦听的本地系统上的端口号。
-
为了确保应用程序使用
multicol
table,将调用switch_table()
函数,该函数使用@@
标记执行伪get
或set
请求。请求中的name
值为bbb
,这是innodb_memcache.containers.name
字段中定义的multicol
table 标识符。
在实际应用程序中可能会使用更具描述性的name
值。本示例仅说明了在get @@...
个请求中指定了 table 标识符而不是 table 名。
-
用于插入和查询数据的 Util 函数演示了如何将 Python 数据结构转换为管道分隔的值,以便通过
add
或set
请求将数据发送到 MySQL,以及如何解压缩get
请求返回的管道分隔值。仅当将单个 memcached 值 Map 到多个 MySQLtable 列时,才需要执行此额外处理。 -
运行示例 Python 应用程序。
shell> python multicol.py
如果成功,示例应用程序将返回以下输出:
Connected to memcached.
Switching default table to 'bbb' by issuing GET for '@@bbb'.
==============================================
Inserting initial data via memcached interface
==============================================
Key = Canada
Value = 34820000|9984670|R
Added new key, value pair.
Key = USA
Value = 314242000|9826675|R
Added new key, value pair.
Key = Ireland
Value = 6399152|84421|L
Added new key, value pair.
Key = UK
Value = 62262000|243610|L
Added new key, value pair.
Key = Mexico
Value = 113910608|1972550|R
Added new key, value pair.
Key = Denmark
Value = 5543453|43094|R
Added new key, value pair.
Key = Norway
Value = 5002942|385252|R
Added new key, value pair.
Key = UAE
Value = 8264070|83600|R
Added new key, value pair.
Key = India
Value = 1210193422|3287263|L
Added new key, value pair.
Key = China
Value = 1347350000|9640821|R
Added new key, value pair.
============================================
Retrieving data for all keys (country names)
============================================
Here is the result retrieved from the database for key Canada:
34820000|9984670|R
Unpacked population value: 34820000
Unpacked area value : 9984670
Unpacked drive side value: R
Here is the result retrieved from the database for key USA:
314242000|9826675|R
Unpacked population value: 314242000
Unpacked area value : 9826675
Unpacked drive side value: R
Here is the result retrieved from the database for key Ireland:
6399152|84421|L
Unpacked population value: 6399152
Unpacked area value : 84421
Unpacked drive side value: L
Here is the result retrieved from the database for key UK:
62262000|243610|L
Unpacked population value: 62262000
Unpacked area value : 243610
Unpacked drive side value: L
Here is the result retrieved from the database for key Mexico:
113910608|1972550|R
Unpacked population value: 113910608
Unpacked area value : 1972550
Unpacked drive side value: R
Here is the result retrieved from the database for key Denmark:
5543453|43094|R
Unpacked population value: 5543453
Unpacked area value : 43094
Unpacked drive side value: R
Here is the result retrieved from the database for key Norway:
5002942|385252|R
Unpacked population value: 5002942
Unpacked area value : 385252
Unpacked drive side value: R
Here is the result retrieved from the database for key UAE:
8264070|83600|R
Unpacked population value: 8264070
Unpacked area value : 83600
Unpacked drive side value: R
Here is the result retrieved from the database for key India:
1210193422|3287263|L
Unpacked population value: 1210193422
Unpacked area value : 3287263
Unpacked drive side value: L
Here is the result retrieved from the database for key China:
1347350000|9640821|R
Unpacked population value: 1347350000
Unpacked area value : 9640821
Unpacked drive side value: R
- 查询
innodb_memcache.containers
table 以查看您先前为multicol
table 插入的记录。第一条记录是在初始daemon_memcached
插件设置期间创建的demo_test
table 的示例条目。第二条记录是您为multicol
table 插入的条目。
mysql> SELECT * FROM innodb_memcache.containers\G
*************************** 1. row ***************************
name: aaa
db_schema: test
db_table: demo_test
key_columns: c1
value_columns: c2
flags: c3
cas_column: c4
expire_time_column: c5
unique_idx_name_on_key: PRIMARY
*************************** 2. row ***************************
name: bbb
db_schema: test
db_table: multicol
key_columns: country
value_columns: population,area_sq_km,drive_side
flags: c3
cas_column: c4
expire_time_column: c5
unique_idx_name_on_key: PRIMARY
- 查询
multicol
table 以查看示例 Python 应用程序插入的数据。该数据可用于 MySQL queries,这演示了如何使用 SQL 或通过应用程序(使用适当的MySQL 连接器或 API)访问相同的数据。
mysql> SELECT * FROM test.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 |
+---------+------------+------------+------------+------+------+------+
Note
在定义被视为数字的列的长度时,请始终留有足够的大小以容纳必要的数字,小数点,符号字符,前导零等。字符串列(例如VARCHAR
)中的太长的值会通过删除一些字符而被截断,这会产生无意义的数字值。
- (可选)在存储 memcached 数据的
InnoDB
table 上运行报告类型的查询。
您可以通过 SQL 查询,跨所有列(不仅是country
键列)执行计算和测试来生成报告。 (因为以下示例仅使用了少数几个国家/locale 的数据,所以这些数字仅用于说明目的.)以下查询将返回右侧行驶的国家/locale 的平均人口数以及名称以“ U”开头的国家/locale 的平均大小“:
mysql> SELECT AVG(population) FROM multicol WHERE drive_side = 'R';
+-------------------+
| avg(population) |
+-------------------+
| 261304724.7142857 |
+-------------------+
mysql> SELECT SUM(area_sq_km) FROM multicol WHERE country LIKE 'U%';
+-----------------+
| sum(area_sq_km) |
+-----------------+
| 10153885 |
+-----------------+
因为population
和area_sq_km
列存储字符数据而不是强类型数字数据,所以AVG()
和SUM()
之类的功能通过首先将每个值转换为数字来工作。例如,当比较基于字符的值9 > 1000
时,这种方法*不适用于<
或>
等运算符,而子句如ORDER BY population DESC
则不希望这样。为了获得最准确的类型处理,请对将数字列转换为适当类型的视图执行查询。通过此技术,您可以从数据库应用程序发出简单的SELECT *
查询,同时确保正确的转换,筛选和排序。以下示例显示了一个视图,可以查询该视图以按人口降序查找前三个国家,其结果反映了multicol
table 中的最新数据,并且人口和面积数字被视为数字:
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;
mysql> SELECT * FROM populous_countries;
+---------+------------+------------+------------+
| country | population | area_sq_km | drive_side |
+---------+------------+------------+------------+
| China | 1347350000 | 9640821 | R |
| India | 1210193422 | 3287263 | L |
| USA | 314242000 | 9826675 | R |
+---------+------------+------------+------------+
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 | |
+------------+---------------------+------+-----+---------+-------+