为InnoDB memcached插件调整现有的MySQL模式
通常,为InnoDB
memcached插件编写应用程序会涉及某种程度的重写或改编使用MySQL或memcached API的现有代码。
- 使用该
daemon_memcached
插件,您可以拥有与MySQL服务器相同数量的内存缓存服务器,而无需运行在低功耗计算机上的许多传统的内存缓存服务器,它们可以在具有大量磁盘存储和内存的功能相对较高的计算机上运行。您可能会重复使用一些与memcached API 一起使用的现有代码,但是由于服务器配置不同,可能需要进行调整。 - 通过
daemon_memcached
插件存储的数据将进入VARCHAR
,TEXT
或BLOB
列,并且必须将其转换为数字运算。您可以在应用程序端执行转换,也可以CAST()
在查询中使用函数。 - 来自数据库背景,您可能习惯于使用具有许多列的通用SQL表。通过内存缓存代码访问的表可能只有几列,甚至只有一列包含数据值。
- 您可以调整应用程序中执行单行查询,插入,更新或删除的部分,以提高关键代码部分的性能。两个查询(读取)和 DML通过执行时(写)操作可以基本上更快
InnoDB
memcached的接口。写入的性能改进通常大于读取的性能改进,因此您可能会专注于改编执行日志记录或在网站上记录交互式选择的代码。
以下各节将更详细地探讨这些要点。
在调整现有的MySQL模式或应用程序以使用插件时,请考虑memcached应用程序的这些方面daemon_memcached
:
- memcached键不能包含空格或换行符,因为这些字符在ASCII协议中用作分隔符。如果您使用查找包含空格的值,用它们作为呼叫键之前变换或哈希他们入值没有空格
add()
,set()
,get()
,等等。尽管从理论上讲,使用二进制协议的程序的键中允许使用这些字符,但是您应限制键中使用的字符,以确保与广泛的客户端兼容。 如果表中有短的数字主键列
InnoDB
,请将其转换为字符串值,将其用作内存缓存的唯一查找键。如果memcached服务器用于多个应用程序或具有多个InnoDB
表,请考虑修改名称以确保其唯一性。例如,将表名或数据库名和表名放在数字值之前。注意
该
daemon_memcached
插件支持在InnoDB
已INTEGER
定义为主键的映射表上进行插入和读取。- 您不能将分区表用于使用memcached查询或存储的数据。
的memcached的协议围绕经过数字值作为字符串。要将数值存储在基础
InnoDB
表中,以实现可在SQL函数(例如SUM()
或)中使用的计数器,AVG()
例如:- 使用
VARCHAR
具有足够字符的列来容纳最大期望数字的所有数字(以及其他字符(如果适用于负号,小数点或两者都适用))。 在使用列值执行算术的任何查询中,请使用
CAST()
函数将值从字符串转换为整数或其他某种数字类型。例如:# Alphabetic entries are returned as zero.
SELECT CAST(c2as 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(c2as unsigned integer))FROM demo_testWHERE 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 numbersAS SELECT c1KEY , CAST(c2AS UNSIGNED INTEGER) valFROM demo_testWHERE c2 BETWEEN '0' and '9999999999';SELECT SUM(val)FROM numbers;注意
通过调用,结果集中的所有字母值都将转换为0
CAST()
。当使用诸如之类的函数时AVG()
,取决于结果集中的行数,请使用includeWHERE
子句过滤掉非数字值。
- 使用
- 如果
InnoDB
用作键的列的值可能超过250个字节,则将该值哈希到小于250个字节。 要将现有表与
daemon_memcached
插件一起使用,请在表中为其定义一个条目innodb_memcache.containers
。要使该表成为所有内存缓存请求的默认表,请default
在该name
列中指定一个值,然后重新启动MySQL服务器以使更改生效。如果您对不同类别的Memcached数据使用多个表,请使用您选择的值在innodb_memcache.containers
表中设置多个条目name
,然后以或的形式发出Memcached请求get @@name
set @@name
在应用程序中指定要用于后续memcached请求的表。有关使用除预定义
test.demo_test
表以外的表的示例,请参见示例15.13“将自己的表与InnoDB内存缓存应用程序一起使用”。有关所需的表布局,请参见“ InnoDB memcached插件内部”。要将多个
InnoDB
表列值与memcached键值对结合使用,请在表条目value_columns
字段中指定用逗号,分号,空格或竖线字符分隔的列名称。例如,在字段中指定或。innodb_memcache.containers
InnoDB
col1,col2,col3
col1|col2|col3
value_columns
在将字符串传递给memcached
add
或set
调用之前,使用管道字符作为分隔符将列值连接为单个字符串。该字符串将自动解压缩到正确的列中。每个get
调用返回一个包含列值的单个字符串,该列值也由竖线字符分隔。您可以使用适当的应用程序语言语法解压缩值。
例15.13将自己的表与InnoDB内存缓存应用程序一起使用
本示例说明如何将自己的表与memcached
用于数据操作的示例Python应用程序一起使用。
该示例假定daemon_memcached
已按照“设置InnoDB memcached插件”中所述安装插件。它还假定您的系统配置为运行使用该python-memcache
模块的Python脚本。
创建
multicol
用于存储国家/地区信息的表格,其中包括人口,面积和驾驶员身侧数据('R'
右侧和'L'
左侧)。mysql>
USE test; mysql>CREATE TABLE `multicol` ( `country` varchar(128) NOT NULLDEFAULT '', `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 =InnoDBDEFAULT CHARSET =utf8mb4;将记录插入
innodb_memcache.containers
表中,以便daemon_memcached
插件可以访问multicol
表。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 ;该表的
innodb_memcache.containers
记录multicol
指定name
值为'bbb'
,这是表标识符。注意
如果将单个
InnoDB
表用于所有内存缓存应用程序,则name
可以将其值设置default
为避免使用@@
符号切换表。- 该
db_schema
列设置为test
,这是multicol
表所在的数据库的名称。 - 该
db_table
列设置为multicol
,这是InnoDB
表的名称。 key_columns
设置为唯一country
列。该country
列被定义为multicol
表定义中的主键。- 而不是单一的
InnoDB
表列,以保存的复合数据值,数据由三个表中的列之间划分(population
,area_sq_km
,和drive_side
)。要容纳多个值列,请在value_columns
字段中指定以逗号分隔的列列表。字段中定义value_columns
的列是存储或检索值时使用的列。 - 对值
flags
,expire_time
以及cas_column
字段基于在所使用的值demo.test
的示例表。这些字段在使用该daemon_memcached
插件的应用程序中通常并不重要,因为MySQL可使数据保持同步,并且无需担心数据过期或过时。 - 该
unique_idx_name_on_key
字段设置为PRIMARY
,表示country
在multicol
表的唯一列上定义的主索引。
将样本Python应用程序复制到文件中。在此示例中,示例脚本被复制到名为的文件中
multicol.py
。示例Python应用程序将数据插入
multicol
表中,并检索所有键的数据,演示了如何InnoDB
通过daemon_memcached
插件访问表。import sys, osimport memcachedef connect_to_memcached(): memc = memcache.Client(['127.0.0.1:11211'], debug=0);print "Connected to memcached."return memcdef banner(message):print print "=" * len(message)print messageprint "=" * 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 = "@@" + tableprint "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 itemin 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 = " + keyprint "Value = " + valueif 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 itemin 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_populationprint "Unpacked area value : " + m_areaprint "Unpacked drive side value: " + m_drive_sideif __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
表,将switch_table()
调用该函数,该函数使用表示法执行虚拟get
或set
请求@@
。所述name
请求中的值是bbb
,这是multicol
在所定义的表标识符innodb_memcache.containers.name
字段。name
在实际应用中可能会使用更具描述性的值。此示例仅说明在get @@...
请求中指定了表标识符而不是表名。- 用于插入和查询数据的实用程序函数演示了如何将Python数据结构转换为管道分隔的值,以便通过
add
或set
请求将数据发送到MySQL ,以及如何解压缩get
请求返回的管道分隔的值。仅当将单个memcached值映射到多个MySQL表列时才需要进行此额外处理。
运行示例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
表以参见您先前为该multicol
表插入的记录。第一条记录是demo_test
在初始daemon_memcached
插件设置过程中创建的表的样本条目。第二条记录是您为multicol
表插入的条目。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
表以参见示例Python应用程序插入的数据。该数据可用于MySQL 查询,这演示了如何使用SQL或通过应用程序(使用适当的MySQL Connector或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 | +--------- +------------ +------------ +------------ +------ +------ +------ +注意
在定义被视为数字的列的长度时,请始终留有足够的大小以容纳必要的数字,小数点,符号字符,前导零等。字符串列(例如a)
VARCHAR
中的太长的值会通过删除一些字符而被截断,这会产生无意义的数值。(可选)在
InnoDB
存储内存缓存数据的表上运行报告类型查询。您可以通过SQL查询,跨任意列(不仅是
country
关键列)执行计算和测试来生成报告。(因为以下示例仅使用了少数几个国家/地区的数据,所以这些数字仅用于说明目的。)以下查询返回右驾车的国家/地区的平均人口数,以及名称以“ U开头的国家/地区的平均大小”:mysql>
SELECT AVG(population)FROM multicolWHERE drive_side = 'R'; +------------------- + | avg(population) | +------------------- + | 261304724.7142857 | +------------------- + mysql>SELECT SUM(area_sq_km)FROM multicolWHERE country LIKE 'U%'; +----------------- + | sum(area_sq_km) | +----------------- + | 10153885 | +----------------- +由于
population
和area_sq_km
列存储字符数据而不是强类型数字数据,因此诸如AVG()
和之类的功能SUM()
通过首先将每个值转换为数字来工作。这种方法不适用于运算符,例如<
或>
,例如,在比较基于字符的值时9 > 1000
,这是从子句中无法期望的ORDER BY population DESC
。为了获得最准确的类型处理,请对将数字列转换为适当类型的视图执行查询。此技术使您发布简单SELECT *
来自数据库应用程序的查询,同时确保正确的转换,筛选和排序。以下示例显示了一个视图,可以查询该视图以按人口降序查找前三个国家,其结果反映了multicol
表中的最新数据,并且人口和面积数字被视为数字:mysql>
CREATE VIEW populous_countriesAS SELECT country, cast(populationas unsigned integer) population, cast(area_sq_kmas unsigned integer) area_sq_km, drive_sideFROM multicolORDER BY CAST(populationas 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 | | +------------ +--------------------- +------ +----- +--------- +------- +