高性能 SQL 计划 Day 5

今天继续学习《MySQL 必知必会》,今天是23章-30章的内容。

Ch 23.使用存储过程

所谓的存储过程,就是在需要针对多个表进行多条SQL语句处理的复杂场合,将多条SQL语句保存成的一个集合。存储过程相当于一个SQL的集合函数,封装了若干条SQL语句。

1.存储过程的优缺点:

存储过程主要有以下优点:

  • 简单

    • 通过把处理封装在容易使用的单元中,简化复杂的操作。
    • 由于不要求反复建立一系列处理步骤,这保证了数据的完整性。
  • 安全

    简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变化,只需要更改存储过程的代码。使用它的人员甚至不需要知道这些变化。通过存储过程可以限制对基础数据的访问,减少了数据讹传。

  • 高性能

    • 提高性能。因为使用存储过程比使用单独的SQL语句要快。
    • 存在一些只能用在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。

存储过程的缺点也很明显:编写存储过程要比编写基本的SQL语句复杂很多;存储过程也往往存在一定的限制,比如只允许用户使用存储过程而不允许创建。

2.使用存储过程

调用存储过程

MySQL 调用执行过程使用的是 CALL关键字,如:

CALL productpricing(@pricelow,
                    @pricehigh,
                    @priceaverage);                    
#CALL 存储过程名(参数列表);

创建存储过程

以下创建了一个简单的无参的存储过程:

CREATE PROCEDURE productpricing()
BEGIN
   SELECT Avg(prod_price) AS priceaverage
   FROM products;
END;

#CREATE PROCEDURE (参数列表)
#BEGIN
#   SQL 语句
#END;

注意:如果使用的是命令行版的MySQL,存储过程体中的SQL语句中的;会被作为分隔符使用,造成错误。解决措施是临时临时更改命令行版MySQL的语句分隔符:

#将分隔符替换为//
DELIMITER //

  CREATE PROCEDURE productpricing()
  BEGIN
     SELECT Avg(prod_price) AS priceaverage
     FROM products;
  END //

  DELIMITER ;
#将分隔符改回;

除了\符号外,其他的符号都可以作为命令行 MySQL 的分隔符。

调用上述存储过程:

CALL productpricing();

删除存储过程

删除上述存储过程:

DROP PROCEDURE productpricing;
#存储过程名后面不需要带()
#仅存在时删除:DROP PROCEDURE IF EXISTS

使用参数

使用存储过程时,常常将结果存储到某个变量里面,因此需要在存储过程中使用参数传递变量:

CREATE PROCEDURE productpricing(
   OUT pl DECIMAL(8,2),
   OUT ph DECIMAL(8,2),
   OUT pa DECIMAL(8,2)
)
BEGIN
   SELECT Min(prod_price)
   INTO pl
   FROM products;
   SELECT Max(prod_price)
   INTO ph
   FROM products;
   SELECT Avg(prod_price)
   INTO pa
   FROM products;
END;

此存储过程接受3个参数:pl存储产品最低价格,ph存储产品最高价格,pa存储产品平均价格。每个参数必须具有指定的类型,这里使用十进制值。关键字OUT指出相应的参数用来从存储过程传出一个值(返回给调用者)。MySQL支持IN(传递给存储过程)、OUT(从存储过程传出,如这里所用)和INOUT(对存储过程传入和传出)类型的参数。存储过程的代码位于BEGIN和END语句内,如前所见,它们是一系列SELECT语句,用来检索值,然后保存到相应的变量(通过指定INTO关键字)。

注意:使用变量时,尤其是对变量进行赋值时需要注意变量的数据类型。

调用上述存储过程,并输出结果:

CALL productpricing(@pricelow,
                    @pricehigh,
                    @priceaverage);
SELECT @priceaverage;                    

注意:所有MySQL变量都需要使用@

以下是一个使用 IN 和 OUT 变量的存储过程:

CREATE PROCEDURE ordertotal(
   IN onumber INT,
   OUT ototal DECIMAL(8,2)
)
BEGIN
   SELECT Sum(item_price*quantity)
   FROM orderitems
   WHERE order_num = onumber
   INTO ototal;
END;

调用上述存储过程并输出结果:

CALL ordertotal(20005,@total);
SELECT @total;

建立智能存储过程

以下是声明了一个复杂存储过程:

-- Name: ordertotal
-- Parameters: onumber = order number
--             taxable = 0 if not taxable, 1 if taxable
--             ototal = order total variable

CREATE PROCEDURE ordertotal(
   IN onumber INT,
   IN taxable BOOLEAN,
   OUT ototal DECIMAL(8,2)
) COMMENT 'Obtain order total, optionally adding tax'
BEGIN

   -- Declare variable for total
   DECLARE total DECIMAL(8,2);
   -- Declare tax percentage
   DECLARE taxrate INT DEFAULT 6;

   -- Get the order total
   SELECT Sum(item_price*quantity)
   FROM orderitems
   WHERE order_num = onumber
   INTO total;

   -- Is this taxable?
   IF taxable THEN
      -- Yes, so add taxrate to the total
      SELECT total+(total/100*taxrate) INTO total;
   END IF;

   -- And finally, save to out variable
   SELECT total INTO ototal;

END;

注意以下几点:

  • 增加了注释 --。在编写复杂的存储过程时,添加一定的注视非常重要。
  • 添加了另外一个参数taxable,它是一个布尔值,传入变量为0或1。
  • 用DECLARE语句定义了两个局部变量。
  • IF语句检查taxable是否为真,如果为真,则用另一SELECT语句增加营业税到局部变量total。最后,用另一SELECT语句将total(它增加或许不增加营业税)保存到ototal。
  • 添加了COMMENT输出信息,相当于日志的作用,其信息将在SHOW PROCEDURE STATUS的结果中显示。

调用上述存储过程,并输出结果:

CALL ordertotal(20005, 0, @total);
SELECT @total;

检查存储过程

查看存储过程的创建语句:

SHOW CREATE PROCEDURE ordertotal;

输出存储过程的详细信息:

SHOW PROCEDURE STATUS;

以上语句会输出全部的存储过程的信息,可以通过以下方式进行过滤:

SHOW PROCEDURE STATUS LIKE 'ordertotal';

Ch 24.使用游标

SQL 检索语句返回的结果称为结果集,之前的操作无法完成这样的操作:获取下一行,获取前十行等等。这就要使用游标了。游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。不同于其他DBMS,MySQL的游标只能用于存储过程。

1.使用游标

使用游标涉及几个明确的步骤:

  • 在能够使用游标前,必须声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的SELECT语句。
  • 一旦声明后,必须打开游标以供使用。这个过程用前面定义的SELECT语句把数据实际检索出来。
  • 对于填有数据的游标,根据需要取出(检索)各行。
  • 在结束游标使用时,必须关闭游标。

在声明游标后,可根据需要频繁地打开和关闭游标。在游标打开后,可根据需要频繁地执行取操作。

定义游标

CREATE PROCEDURE processorders()
BEGIN
   DECLARE ordernumbers CURSOR
   FOR
   SELECT ordernum FROM orders;
END;

游标的命名方式为DECLARE 游标名 CURSOR,需要注意的是,存储过程执行完毕后游标就消失。

打开和关闭游标

#打开游标
OPEN ordernumbers;

#关闭游标
CLOSE ordernumbers;

注意:只有打开游标后才能使用它,在游标使用完毕后需要关闭它以释放资源。即使不手动关闭游标,当存储过程执行完毕游标也会被 MySQL 关闭。

CREATE PROCEDURE processorders()
BEGIN
   -- Declare the cursor
   DECLARE ordernumbers CURSOR
   FOR
   SELECT order_num FROM orders;

   -- Open the cursor
   OPEN ordernumbers;

   -- Close the cursor
   CLOSE ordernumbers;

END;

使用游标数据

在一个游标被打开后,可以使用FETCH语句分别访问它的每一行。FETCH指定检索什么数据(所需的列),检索出来的数据存储在什么地方。它还向前移动游标中的内部行指针,使下一条FETCH语句检索下一行(不重复读取同一行)。

第一个例子是利用FETCH检索第一行

CREATE PROCEDURE processorders()
BEGIN

   -- Declare local variables
   DECLARE o INT;

   -- Declare the cursor
   DECLARE ordernumbers CURSOR
   FOR
   SELECT order_num FROM orders;

   -- Open the cursor
   OPEN ordernumbers;

   -- Get order number
   --将检索出的数据存放在局部变量o中
   FETCH ordernumbers INTO o;

   -- Close the cursor
   CLOSE ordernumbers;

END;

下一个例子是循环检索数据,从第一行到最后一行

CREATE PROCEDURE processorders()
BEGIN

   -- Declare local variables
   DECLARE done BOOLEAN DEFAULT 0;
   DECLARE o INT;

   -- Declare the cursor
   DECLARE ordernumbers CURSOR
   FOR
   SELECT order_num FROM orders;

   -- Declare continue handler
   -- SQLSTATE '02000'指的是未找到的错误,强行类比的话像是NullPointerException
   DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

   -- Open the cursor
   OPEN ordernumbers;

   -- Loop through all rows
   REPEAT

      -- Get order number
      FETCH ordernumbers INTO o;

   -- End of loop
   UNTIL done END REPEAT;

   -- Close the cursor
   CLOSE ordernumbers;

END;

注意:DECLARE语句的发布存在特定的次序。用DECLARE语句定义的局部变量必须在定义任意游标或句柄之前定义,而句柄必须在游标之后定义。不遵守此顺序将产生错误消息。
接下来是一个复杂的例子,其中ordertotal是上一章定义的一个计算税率的存储过程:

CREATE PROCEDURE processorders()
BEGIN

   -- Declare local variables
   DECLARE done BOOLEAN DEFAULT 0;
   DECLARE o INT;
   DECLARE t DECIMAL(8,2);

   -- Declare the cursor
   DECLARE ordernumbers CURSOR
   FOR
   SELECT order_num FROM orders;
   -- Declare continue handler
   DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

   -- Create a table to store the results
   CREATE TABLE IF NOT EXISTS ordertotals
      (order_num INT, total DECIMAL(8,2));

   -- Open the cursor
   OPEN ordernumbers;

   -- Loop through all rows
   REPEAT

      -- Get order number
      FETCH ordernumbers INTO o;

      -- Get the total for this order
      CALL ordertotal(o, 1, t);

      -- Insert order and total into ordertotals
      INSERT INTO ordertotals(order_num, total)
      VALUES(o, t);

   -- End of loop
   UNTIL done END REPEAT;

   -- Close the cursor
   CLOSE ordernumbers;

END;

在这个存储过程中,将检索出来的数据存储到新表中。

Ch 25.使用触发器

如果想使得某些语句在一些事件发生后自动执行,如每当订购一个产品时,都从库存数量中减去订购的数量;无论何时删除一行,都在某个存档表中保留一个副本。想要完成这样的操作,就要使用触发器。

触发器是MySQL响应以下任意语句而自动执行的一组MySQL语句:

  • DELETE;
  • INSERT;
  • UPDATE。

其他MySQL语句不支持触发器。

1.创建触发器

创建触发器需要提供以下信息:

  • 唯一的触发器名;
  • 触发器关联的表;
  • 触发器应该响应的活动(DELETE、INSERT或UPDATE);
  • 触发器何时执行(处理之前或之后)。

需要注意的是,最好是保持每个数据库的触发器名唯一。另外,只有表支持触发器,视图不支持、临时表也不支持。

CREATE TRIGGER newproduct AFTER INSERT ON products
FOR EACH ROW SELECT 'Product added';

上述语句对 products 定义了一个触发器,每当对该表进行插入操作后,对每个插入行显示“Product added”消息。

MySQL 触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。因此,每个表最多支持6个触发器,即INSERT、DELETE、UPDATE的执行前和执行后。

注意:在MySQL中,如果BEFORE触发器失败,则不会执行请求的操作;如果BEFORE触发器失败或者语句本身失败,也不会执行AFTER触发器操作。

2.删除触发器

DROP TRIGGER newproduct;

3.使用触发器

INSERT触发器

INSERT触发器在INSERT语句执行之前或之后执行。需要知道以下几点:

  • 在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;
  • 在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值);
  • 对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。
CREATE TRIGGER neworder AFTER INSERT ON orders
FOR EACH ROW SELECT NEW.order_num;

上述语句定义了一个 neworder 的触发器,在对orders表进行插入操作后对于每个插入行显示该新插入记录的order_num属性值。

#运行如下语句
INSERT INTO orders(order_date, cust_id)
VALUES(Now(), 10001);

#可得到如下输出
+-----------+
| order_num |
+-----------+
|     20010 |
+-----------+

注意:BEFORE触发器多用于数据的验证和净化,而AFTER触发器多用于显示提示信息。

DELETE触发器

DELETE触发器在DELETE语句执行之前或之后执行。需要知道以下两点:

  • 在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行;
  • OLD中的值全都是只读的,不能更新。

下面的例子演示使用OLD将要被删除的行保存到一个存档表中:

CREATE TRIGGER deleteorder BEFORE DELETE ON orders
FOR EACH ROW
BEGIN
   INSERT INTO archive_orders(order_num, order_date, cust_id)
   VALUES(OLD.order_num, OLD.order_date, OLD.cust_id);
END;
#触发器体可以使用BEGIN和END包裹多条SQL语句。

根据前文所提到的,如果BEFORE触发器执行失败,则说明存档失败,因此不会执行删除操作。

UPDATE触发器

UPDATE触发器在UPDATE语句执行之前或之后执行。需要知道以下几点:

  • 在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新更新的值;
  • 在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);
  • OLD中的值全都是只读的,不能更新。

下面的例子保证州名缩写总是大写(不管UPDATE语句中给出的是大写还是小写):

CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors
FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);

注意事项

以下是原书中所写的触发器注意事项:

  • 与其他DBMS相比,MySQL5中支持的触发器相当初级。未来的MySQL版本中有一些改进和增强触发器支持的计划。
  • 创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果INSERT、UPDATE或DELETE语句能够执行,则相关的触发器也能执行。
  • 应该用触发器来保证数据的一致性(大小写、格式等)。在触发器中执行这种类型的处理的优点是它总是进行这种处理,而且是透明地进行,与客户机应用无关。
  • 触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,把更改(如果需要,甚至还有之前和之后的状态)记录到另一个表非常容易。
  • 遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。

Ch 26.管理事务处理

正如前文所讲的,并非所有的数据库引擎都支持事务处理,MySQL最常用的引擎中,InnoDB支持事务而MyISAM不支持。

事务处理(transactionprocessing)可以用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行,以保证数据库不包含不完整的操作结果。如果没有错误发生,整组语句提交给(写到)数据库表。如果发生错误,则进行回退(撤销)以恢复数据库到某个已知且安全的状态。

首先定义几个概念:

  • 事务(transaction)指一组SQL语句;
  • 回退(rollback)指撤销指定SQL语句的过程;
  • 提交(commit)指将未存储的SQL语句结果写入数据库表;
  • 保留点(savepoint)指事务处理中设置的临时占位符(place-holder),你可以对它发布回退(与回退整个事务处理不同)。

1.控制事务处理

管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。
MySQL使用下面的语句来标识事务的开始:

START TRANSACTION

使用ROLLBACK

SELECT * FROM ordertotals;
START TRANSACTION;
DELETE FROM ordertotals;
SELECT * FROM ordertotals;
ROLLBACK;
SELECT * FROM ordertotals;

上述语句开启事务后将ordertotals表中的记录全部删除,然后回滚事务,将数据库状态恢复至刚刚开启事务时。

注意:只能回退INSERT、UPDATE、DELETE语句,SELECT语句回退没有意义。不能回退CREATE和DROP,虽然可以在事务处理块中使用这两种语句,但是执行回退他们不会被撤销。

使用COMMIT

一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交(implicitcommit),即提交(写或保存)操作是自动进行的。但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交,使用COMMIT语句。

START TRANSACTION;
DELETE FROM orderitems WHERE order_num = 20010;
DELETE FROM orders WHERE order_num = 20010;
COMMIT;

最后的COMMIT语句仅在不出错时写出更改。如果第一条DELETE起作用,但第二条失败,则DELETE不会提交(实际上,它是被自动撤销的)。

注意:当COMMIT或ROLLBACK语句执行后,事务会自动关闭(将来的更改会隐含提交)。

使用保留点

更复杂的事务处理可能需要部分提交或回退,为了支持回退部分事务处理,必须能在事务处理块中合适的位置放置占位符。这样,如果需要回退,可以回退到某个占位符。这些占位符称为保留点。为了创建占位符,可如下使用SAVEPOINT语句:

SAVEPOINT delete1;

#回退到保留点
ROLLBACK TO delete1;

注意:在进行复杂的事务操作时,可以尽可能多地设置保留点,这样可以灵活回退。保留点在事务完成后会自动释放,但也可以使用RELEASE SAVEPOINT明确地释放保留点。

2.更改默认的自动提交

默认的MySQL行为是自动提交所有更改。换句话说,任何时候你执行一条MySQL语句,该语句实际上都是针对表执行的,而且所做的更改立即生效。为指示MySQL不自动提交更改,需要使用以下语句:

SET autocommit=0;

注意:autocommit标志是针对每个连接而不是服务器的。

Ch 27.全球化和本地化

1.使用字符集和校正顺序

查看MySQL所支持字符集的完整列表:

SHOW CHARACTER SET;

查看所支持的校正顺序的完整列表:

SHOW COLLATION;

确定所使用的字符集和校正顺序:

SHOW VARIABLES LIKE 'character%';
SHOW VARIABLES LIKE 'collation%';

在创建表时指定字符集和校正顺序:

CREATE TABLE mytable
(
   columnn1   INT,
   columnn2   VARCHAR(10)
) DEFAULT CHARACTER SET hebrew
  COLLATE hebrew_general_ci;

一般,MySQL如下确定使用什么样的字符集和校对:

  • 如果指定CHARACTER SET和COLLATE两者,则使用这些值。
  • 如果只指定CHARACTER SET,则使用此字符集及其默认的校对(如SHOW CHARACTER SET的结果中所示)。
  • 如果既不指定CHARACTER SET,也不指定COLLATE,则使用数据库默认。

MySQL还允许对每个列设置字符集和校正顺序:

CREATE TABLE mytable
(
   columnn1   INT,
   columnn2   VARCHAR(10),
   column3    VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_general_ci
) DEFAULT CHARACTER SET hebrew
  COLLATE hebrew_general_ci;

校对在对用ORDER BY子句检索出来的数据排序时起重要的作用。如果你需要用与创建表时不同的校对顺序排序特定的SELECT语句,可以在SELECT语句自身中进行:

SELECT * FROM customers
ORDER BY lastname, firstname COLLATE latin1_general_cs;

Ch 28.安全管理

1.访问控制

MySQL服务器的安全基础是:用户应该对他们需要的数据具有适当的访问权,既不能多也不能少

MySQL默认数据库的用户root拥有对数据库的绝对管理权限,应该严肃对待root登录的使用。仅在绝对需要时使用它(或许在你不能登录其他管理账号时使用)。不应该在日常的MySQL操作中使用root。

2.管理用户

MySQL用户账号和信息存储在名为mysql的MySQL数据库中。可以在其中的user表中查询到所有的用户:

USE mysql;
SELECT user FROM user;

创建用户

CREATE USER ben IDENTIFIED BY 'p@$$w0rd';

重命名用户

RENAME USER ben TO bforta;

删除用户

DROP USER bforta;

设置访问权限

新创建的用户没有任何权限,只能登录服务器,不能操作任何表和数据库。

查看权限:

SHOW GRANTS FOR bforta;

#输出为
+-------------------------------------------------+
| Grants for bforta@%                             |
+-------------------------------------------------+
| GRANT USAGE ON *.* TO 'bforta'@'%'              |
+-------------------------------------------------+

ON*.*表示在任意数据库和任意表上对任何东西没有权限。

另外,“MySQL的权限用用户名和主机名结合定义,即user@host。如果不指定主机名,则使用默认的主机名%(授予用户访问权限而不管主机名)。

可以使用 GRANT 语句授予用户权限,

  • 要授予的权限;
  • 被授予访问权限的数据库或表;
  • 用户名。

以下例子给出GRANT的用法:

GRANT SELECT ON crashcourse.* TO beforta;

这条语句授予beforta用户对crashcourse数据库中所有的表上使用SELECT语句的权限。

可以使用REVOKE语句来撤销GRANT授予的权限:

REVOKE SELECT ON crashcourse.* FROM beforta

GRANT和REVOKE可在几个层次上控制访问权限:

  • 整个服务器,使用GRANT ALL和REVOKE ALL;
  • 整个数据库,使用ON database.*;
  • 特定的表,使用ON database.table;
  • 特定的列;
  • 特定的存储过程。

以下是具体权限内容:

可通过列出各权限并用逗号分隔,将多条GRANT语句串在一起,如下所示:

GRANT SELECT, INSERT ON crashcourse.* TO beforta;

更改口令

可以使用下列语句更改口令:

SET PASSWORD FOR bforta = Password('n3w p@$$w0rd');

新口令必须传递到Password()函数进行加密。

Ch 29.数据库维护

1.备份数据

对数据库进行备份主要有以下几种方式:

  • 在MySQL命令行使用mysqldump将所有数据库内容存储到某个外部文件中;
  • 在MySQL命令行使用mysqlhotcopy从一个数据库复制所有数据(并非所有的数据库引擎都支持);
  • 可以使用MySQL的BACKUP TABLESELECT INTO OUTFILE转储所有数据到某个外部文件。数据可以用RESTORE TABLE来复原。

注意:为了保证所有数据被写到磁盘(包括索引数据),可能需要在进行备份前使用FLUSH TABLES语句。

2.进行数据库维护

应该知道以下语句:

ANALYZE TABLE,用来检查表键是否正确。ANALYZE TABLE返回如下所示的状态信息:

ANALYZE TABLE orders;

CHECK TABLE用来针对许多问题对表进行检查。CHECK TABLE支持一系列的用于MyISAM引擎表的方式。CHANGED检查自最后一次检查以来改动过的表。EXTENDED执行最彻底的检查,FAST只检查未正常关闭的表,MEDIUM检查所有被删除的链接并进行键检验,QUICK只进行快速扫描。如下所示,CHECK TABLE发现和修复问题:

CHECK TABLE orders, orderitems;

3.诊断启动问题

在排除系统启动问题时,首先应该尽量用手动启动服务器。MySQL服务器自身通过在命令行上执行mysqld启动。下面是几个重要的mysqld命令行选项:

  • --help显示帮助——一个选项列表;
  • --safe-mode装载减去某些最佳配置的服务器;
  • --verbose显示全文本消息(为获得更详细的帮助消息与--help联合使用);
  • --version显示版本信息然后退出。

4.查看日志文件

MySQL维护管理员依赖的一系列日志文件。主要的日志文件有以下几种:

  • 错误日志。它包含启动和关闭问题以及任意关键错误的细节。此日志通常名为hostname.err,位于data目录中。此日志名可用--log-error命令行选项更改。
  • 查询日志。它记录所有MySQL活动,在诊断问题时非常有用。此日志文件可能会很快地变得非常大,因此不应该长期使用它。此日志通常名为hostname.log,位于data目录中。此名字可以用--log命令行选项更改。
  • 二进制日志。它记录更新过数据(或者可能更新过数据)的所有语句。此日志通常名为hostname-bin,位于data目录内。此名字可以用--log-bin命令行选项更改。注意,这个日志文件是MySQL 5中添加的,以前的MySQL版本中使用的是更新日志。
  • 缓慢查询日志。顾名思义,此日志记录执行缓慢的任何查询。这个日志在确定数据库何处需要优化很有用。此日志通常名为hostname-slow.log,位于data目录中。此名字可以用--log-slow-queries命令行选项更改。

Ch 30.改善性能

数据库管理员把他们生命中的相当一部份时间花在了调整、试验以改善DBMS性能之上。在诊断应用的滞缓现象和性能问题时,性能不良的数据库(以及数据库查询)通常是最常见的祸因。

回顾之前的章节,总结了一下的几个性能Tips:

  • 首先,MySQL(与所有DBMS一样)具有特定的硬件建议。在学习和研究MySQL时,使用任何旧的计算机作为服务器都可以。但对用于生产的服务器来说,应该坚持遵循这些硬件建议。
  • 一般来说,关键的生产DBMS应该运行在自己的专用服务器上。
  • MySQL是用一系列的默认设置预先配置的,从这些设置开始通常是很好的。但过一段时间后你可能需要调整内存分配、缓冲区大小等。(为查看当前设置,可使用SHOW VARIABLES;和SHOW STATUS;。)
  • MySQL是一个多用户多线程的DBMS,换言之,它经常同时执行多个任务。如果这些任务中的某一个执行缓慢,则所有请求都会执行缓慢。如果你遇到显著的性能不良,可使用SHOW PROCESS LIST显示所有活动进程(以及它们的线程ID和执行时间)。你还可以用KILL命令终结某个特定的进程(使用这个命令需要作为管理员登录)。
  • 总是有不止一种方法编写同一条SELECT语句。应该试验联结、并、子查询等,找出最佳的方法。
  • 使用EXPLAIN语句让MySQL解释它将如何执行一条SELECT语句。
  • 一般来说,存储过程执行得比一条一条地执行其中的各条MySQL语句快。
  • 应该总是使用正确的数据类型。
  • 决不要检索比需求还要多的数据。换言之,不要用SELECT*(除非你真正需要每个列)。
  • 有的操作(包括INSERT)支持一个可选的DELAYED关键字,如果使用它,将把控制立即返回给调用程序,并且一旦有可能就实际执行该操作。
  • 在导入数据时,应该关闭自动提交。你可能还想删除索引(包括FULLTEXT索引),然后在导入完成后再重建它们。
  • 必须索引数据库表以改善数据检索的性能。确定索引什么不是一件微不足道的任务,需要分析使用的SELECT语句以找出重复的WHERE和ORDER BY子句。如果一个简单的WHERE子句返回结果所花的时间太长,则可以断定其中使用的列(或几个列)就是需要索引的对象。
  • 你的SELECT语句中有一系列复杂的OR条件吗?通过使用多条SELECT语句和连接它们的UNION语句,你能看到极大的性能改进。
  • 索引改善数据检索的性能,但损害数据插入、删除和更新的性能。如果你有一些表,它们收集数据且不经常被搜索,则在有必要之前不要索引它们。(索引可根据需要添加和删除。)
  • LIKE很慢。一般来说,最好是使用FULLTEXT而不是LIKE。
  • 数据库是不断变化的实体。一组优化良好的表一会儿后可能就面目全非了。由于表的使用和内容的更改,理想的优化和配置也会改变。
  • 最重要的规则就是,每条规则在某些条件下都会被打破。

以上差不多就是《MySQL 必知必会》这本书的全部内容了,这本书深入浅出对MySQL数据库进行了一个整体的介绍。但是我们的高性能SQL的计划才刚刚开始。

未完待续······

你可能感兴趣的:(高性能 SQL 计划 Day 5)