• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • 为InnoDB memcached插件调整现有的MySQL模式

    通常,为InnoDBmemcached插件编写应用程序会涉及某种程度的重写或改编使用MySQL或memcached API的现有代码。

    • 使用该daemon_memcached插件,您可以拥有与MySQL服务器相同数量的内存缓存服务器,而无需运行在低功耗计算机上的许多传统的内存缓存服务器,它们可以在具有大量磁盘存储和内存的功能相对较高的计算机上运行。您可能会重复使用一些与memcached API 一起使用的现有代码,但是由于服务器配置不同,可能需要进行调整。
    • 通过daemon_memcached插件存储的数据将进入VARCHARTEXTBLOB列,并且必须将其转换为数字运算。您可以在应用程序端执行转换,也可以CAST()在查询中使用函数。
    • 来自数据库背景,您可能习惯于使用具有许多列的通用SQL表。通过内存缓存代码访问的表可能只有几列,甚至只有一列包含数据值。
    • 您可以调整应用程序中执行单行查询,插入,更新或删除的部分,以提高关键代码部分的性能。两个查询(读取)和 DML通过执行时(写)操作可以基本上更快InnoDBmemcached的接口。写入的性能改进通常大于读取的性能改进,因此您可能会专注于改编执行日志记录或在网站上记录交互式选择的代码。

    以下各节将更详细地探讨这些要点。

    在调整现有的MySQL模式或应用程序以使用插件时,请考虑memcached应用程序的这些方面daemon_memcached

    • memcached键不能包含空格或换行符,因为这些字符在ASCII协议中用作分隔符。如果您使用查找包含空格的值,用它们作为呼叫键之前变换或哈希他们入值没有空格add()set()get(),等等。尽管从理论上讲,使用二进制协议的程序的键中允许使用这些字符,但是您应限制键中使用的字符,以确保与广泛的客户端兼容。
    • 如果表中有短的数字主键列InnoDB,请将其转换为字符串值,将其用作内存缓存的唯一查找键。如果memcached服务器用于多个应用程序或具有多个InnoDB表,请考虑修改名称以确保其唯一性。例如,将表名或数据库名和表名放在数字值之前。

      注意

      daemon_memcached插件支持在InnoDBINTEGER定义为主键的映射表上进行插入和读取。

    • 您不能将分区表用于使用memcached查询或存储的数据。
    • memcached的协议围绕经过数字值作为字符串。要将数值存储在基础InnoDB表中,以实现可在SQL函数(例如SUM()或)中使用的计数器,AVG()例如:

      • 使用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;
        
        注意

        通过调用,结果集中的所有字母值都将转换为0 CAST()。当使用诸如之类的函数时AVG(),取决于结果集中的行数,请使用include WHERE子句过滤掉非数字值。

    • 如果InnoDB用作键的列的值可能超过250个字节,则将该值哈希到小于250个字节。
    • 要将现有表与daemon_memcached插件一起使用,请在表中为其定义一个条目innodb_memcache.containers。要使该表成为所有内存缓存请求的默认表,请default在该name列中指定一个值,然后重新启动MySQL服务器以使更改生效。如果您对不同类别的Memcached数据使用多个表,请使用您选择的值在innodb_memcache.containers表中设置多个条目name,然后以或的形式发出Memcached请求get @@nameset @@name在应用程序中指定要用于后续memcached请求的表。

      有关使用除预定义test.demo_test表以外的表的示例,请参见示例15.13“将自己的表与InnoDB内存缓存应用程序一起使用”。有关所需的表布局,请参见“ InnoDB memcached插件内部”。

    • 要将多个InnoDB表列值与memcached键值对结合使用,请在表条目value_columns字段中指定用逗号,分号,空格或竖线字符分隔的列名称。例如,在字段中指定或。innodb_memcache.containersInnoDBcol1,col2,col3col1|col2|col3value_columns

      在将字符串传递给memcachedaddset调用之前,使用管道字符作为分隔符将列值连接为单个字符串。该字符串将自动解压缩到正确的列中。每个get调用返回一个包含列值的单个字符串,该列值也由竖线字符分隔。您可以使用适当的应用程序语言语法解压缩值。

    例15.13将自己的表与InnoDB内存缓存应用程序一起使用

    本示例说明如何将自己的表与memcached用于数据操作的示例Python应用程序一起使用。

    该示例假定daemon_memcached已按照“设置InnoDB memcached插件”中所述安装插件。它还假定您的系统配置为运行使用该python-memcache模块的Python脚本。

    1. 创建multicol用于存储国家/地区信息的表格,其中包括人口,面积和驾驶员身侧数据('R'右侧和'L'左侧)。

      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=utf8mb4;
      
    2. 将记录插入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表列,以保存的复合数据值,数据由三个表中的列之间划分(populationarea_sq_km,和drive_side)。要容纳多个值列,请在value_columns字段中指定以逗号分隔的列列表。字段中定义value_columns的列是存储或检索值时使用的列。
      • 对值flagsexpire_time以及cas_column字段基于在所使用的值demo.test的示例表。这些字段在使用该daemon_memcached插件的应用程序中通常并不重要,因为MySQL可使数据保持同步,并且无需担心数据过期或过时。
      • unique_idx_name_on_key字段设置为PRIMARY,表示countrymulticol表的唯一列上定义的主索引。
    3. 将样本Python应用程序复制到文件中。在此示例中,示例脚本被复制到名为的文件中multicol.py

      示例Python应用程序将数据插入multicol表中,并检索所有键的数据,演示了如何InnoDB通过daemon_memcached插件访问表。

      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表,将switch_table()调用该函数,该函数使用表示法执行虚拟getset请求@@。所述name请求中的值是bbb,这是multicol在所定义的表标识符innodb_memcache.containers.name字段。

        name在实际应用中可能会使用更具描述性的值。此示例仅说明在get @@...请求中指定了表标识符而不是表名。

      • 用于插入和查询数据的实用程序函数演示了如何将Python数据结构转换为管道分隔的值,以便通过addset请求将数据发送到MySQL ,以及如何解压缩get请求返回的管道分隔的值。仅当将单个memcached值映射到多个MySQL表列时才需要进行此额外处理。
    4. 运行示例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
      
    5. 查询该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
      
    6. 查询该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中的太长的值会通过删除一些字符而被截断,这会产生无意义的数值。

    7. (可选)在InnoDB存储内存缓存数据的表上运行报告类型查询。

      您可以通过SQL查询,跨任意列(不仅是country关键列)执行计算和测试来生成报告。(因为以下示例仅使用了少数几个国家/地区的数据,所以这些数字仅用于说明目的。)以下查询返回右驾车的国家/地区的平均人口数,以及名称以“ U开头的国家/地区的平均大小”:

      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 	|
      +-----------------	+
      

      由于populationarea_sq_km列存储字符数据而不是强类型数字数据,因此诸如AVG()和之类的功能SUM()通过首先将每个值转换为数字来工作。这种方法不适用于运算符,例如<>,例如,在比较基于字符的值时9 > 1000,这是从子句中无法期望的ORDER BY population DESC。为了获得最准确的类型处理,请对将数字列转换为适当类型的视图执行查询。此技术使您发布简单SELECT *来自数据库应用程序的查询,同时确保正确的转换,筛选和排序。以下示例显示了一个视图,可以查询该视图以按人口降序查找前三个国家,其结果反映了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;
      
      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    	|       	|
      +------------	+---------------------	+------	+-----	+---------	+-------	+