第17章:MySQL簇 / 17.3. 多计算机的简单基础知识 / 17.3.5. 加载示例数据并执行查询

与没有使用簇的MySQL相比,在MySQL簇内操作数据的方式没有太大的区别。执行这类操作时应记住两点:

·         表必须用ENGINE=NDBENGINE=NDBCLUSTER选项创建,或用ALTER TABLE选项更改,以使用NDB簇存储引擎在簇内复制它们。如果使用mysqldump的输出从已有数据库导入表,可在文本编辑器中打开SQL脚本,并将该选项添加到任何表创建语句,或用这类选项之一替换任何已有的ENGINE(或TYPE)选项。例如,假定在另一个MySQL服务器(不支持MySQL簇)上有样本世界数据库,而且你打算导出城市表的定义:

·                shell> mysqldump --add-drop-table world City > city_table.sql

在所得的city_table.sql文件中,将包含这条表创建语句(以及导入表数据所需的INSERT语句):

DROP TABLE IF EXISTS City;
CREATE TABLE City (
ID int(11) NOT NULL auto_increment,
Name char(35) NOT NULL default '',
CountryCode char(3) NOT NULL default '',
District char(20) NOT NULL default '',
Population int(11) NOT NULL default '0',
PRIMARY KEY  (ID)
) ENGINE=MyISAM;
 
INSERT INTO City VALUES (1,'Kabul','AFG','Kabol',1780000);
INSERT INTO City VALUES (2,'Qandahar','AFG','Qandahar',237500);
INSERT INTO City VALUES (3,'Herat','AFG','Herat',186800);
# (remaining INSERT statements omitted)

需要确认MySQL为该表使用了NDB存储引擎。有两种完成该任务的方法。其中一种方法是,在将表导入簇数据库之前更改其定义,使其类似于(仍使用“城市”作为示例):

DROP TABLE IF EXISTS City;
CREATE TABLE City (
ID int(11) NOT NULL auto_increment,
Name char(35) NOT NULL default '',
CountryCode char(3) NOT NULL default '',
District char(20) NOT NULL default '',
Population int(11) NOT NULL default '0',
PRIMARY KEY  (ID)
) ENGINE=NDBCLUSTER;
 
INSERT INTO City VALUES (1,'Kabul','AFG','Kabol',1780000);
INSERT INTO City VALUES (2,'Qandahar','AFG','Qandahar',237500);
INSERT INTO City VALUES (3,'Herat','AFG','Herat',186800);
# (etc.)

对于将成为簇数据库组成部份的每个表,均需要为其定义执行上述操作。完成该任务的最简单方法是,简单地在world.sql文件上执行查找-替换,并用ENGINE=NDBCLUSTER替换所有的TYPE=MyISAM实例。如果你不打算更改该文件,也可使用ALTER TABLE。详情请参见下面的介绍。

假定你已在簇的SQL节点上创建了名为“world”的数据库,随后可使用mysql命令行客户端读取city_table.sql,并按通常方式创建和填充对应的表:

shell> mysql world < city_table.sql

请记住,上述命令必须在运行SQL节点的主机上执行,这点十分重要。对于本例,应在IP地址为192.168.0.20的机器上执行。

要想在SQL节点上创建世界数据库的副本,请将文件保存到/usr/local/mysql/data,然后运行:

shell> cd /usr/local/mysql/data
shell> mysql world < world.sql

当然,SQL脚本必须能被mysql系统用户读取。如果将文件保存到了不同的目录下,请作相应的调整。

注意,在MySQL 5.1中,NDB簇不支持自动发现数据库的功能,这点很重要(请参见17.8节,“MySQL簇的已知限制”)。这意味着,一旦在一个数据节点上创建了世界(world)数据库和它的表,在簇中的每个SQL节点上还需要发出命令CREATE DATABASE world(从MySQL 5.0.2开始,可以使用CREATE SCHEMA world取而代之),后跟FLUSH TABLES。这样,节点就能识别数据库并读取其表定义。

SQL节点上运行SELECT查询与在MySQL服务器的任何其他实例上运行查询没有区别。要想从命令行运行查询,首先应按照通常方式登录到MySQL监视器:

shell> mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 5.1.2-alpha
 
键入’help;’或’\h’获取帮助。键入’\c’清空缓冲区。
 
mysql>

如果在导入MySQL脚本之前未更改表定义中的ENGINE=子句,应在此时运行下述命令:

mysql> USE world;
mysql> ALTER TABLE City ENGINE=NDBCLUSTER;
mysql> ALTER TABLE Country ENGINE=NDBCLUSTER;
mysql> ALTER TABLE CountryLanguage ENGINE=NDBCLUSTER;

注意,在这里我们简单地使用了MySQL服务器密码为空的默认根用户账户。当然,在生产设置下,安装MySQL服务器时,总应遵守标准的安全方法措施,包括设置牢靠的根用户密码,并为用户创建具有完成任务所需的权限的用户账户。关于这方面的更多信息,请参见5.7节,“MySQL访问权限系统”

需要关注的是,当簇节点彼此访问时不使用MySQL的权限系统,设置或更改MySQL用户账户(包括根用户账户)不影响节点之间的交互,它们仅对访问SQL节点的应用程序有效。

能够以通常的方式选择数据库,并对表执行SELECT查询,就像退出MySQL监视器一样:

mysql> USE world;
mysql> SELECT Name, Population FROM City ORDER BY Population DESC LIMIT 5;
+-----------+------------+
| 名称      | 人口 |
+-----------+------------+
| 孟买      |   10500000 |
| 汉城      |    9981619 |
| 圣保罗    |    9968485 |
| 上海      |    9696300 |
| 雅加达    |    9604900 |
+-----------+------------+
5 rows in set (0.34 sec)
 
mysql> \q
Bye
 
shell>

使用MySQL的应用程序能够使用标准的API。重要的是应记住,你的应用程序必须访问SQL节点,而不是MGM或存储节点。在下面的简单示例中,介绍了使用PHP 5mysqli扩展(运行在位于网络中其他位置的Web服务器上)执行相同查询的方法:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type"
        content="text/html; charset=iso-8859-1">
  <title>SIMPLE mysqli SELECT</title>
</head>
<body>
<?php
  # connect to SQL node:
  $link = new mysqli('192.168.0.20', 'root', '', 'world');
  # parameters for mysqli constructor are:
  #   host, user, password, database
 
  if( mysqli_connect_errno() )
    die("Connect failed: " . mysqli_connect_error());
 
  $query = "SELECT Name, Population
            FROM City
            ORDER BY Population DESC
            LIMIT 5";
 
  # if no errors...
  if( $result = $link->query($query) )
  {
?>
<table border="1" width="40%" cellpadding="4" cellspacing ="1">
  <tbody>
  <tr>
    <th width="10%">City</th>
    <th>Population</th>
  </tr>
<?
    # then display the results...
    while($row = $result->fetch_object())
      printf(<tr>\n  <td align=\"center\">%s</td><td>%d</td>\n</tr>\n",
              $row->Name, $row->Population);
?>
  </tbody
</table>
<?
  # ...and verify the number of rows that were retrieved
    printf("<p>Affected rows: %d</p>\n", $link->affected_rows);
  }
  else
    # otherwise, tell us what went wrong
    echo mysqli_error();
 
  # free the result set and the mysqli connection object
  $result->close();
  $link->close();
?>
</body>
</html>

我们假定运行在Web服务器上的进程能够访问SQL节点的IP地址。

采用类似的风格,可以使用MySQL C APIPerl-DBIPython-mysql、或MySQL AB自己的连接器来执行数据定义和操控任务,就像正常使用MySQL那样。

·         另外还请记住,每个NDB必须有一个主键。如果在创建表时用户未定义主键,NDB簇存储引擎将自动生成隐含的主键。(注释:该隐含 键也将占用空间,就像任何其他的表索引一样。由于没有足够的内存来容纳这些自动创建的键,出现问题并不罕见)。