查询字段[置顶] 优化MySQL数据库性能的八种方法

最近应用开发的程过中现出了一个小问题,顺便记载一下原因和法方--查询字段

    1、选取最实用的字段属性

    MySQL可以很好的持支大据数量的取存,但是一般说来,据数库中的表越小,在它下面行执的查询也就会越快。因此,在建创表的时候,为了得获更好的能性,我们可以将表中字段的宽度设得尽可能小。例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),然显给据数库增加了不必要的空间,甚至应用VARCHAR种这类型也是余多的,因为CHAR(6)以可就很好的成完任务了。样同的,如果可以的话,我们应当应用MEDIUMINT而不是BIGIN来定义整型字段。

    另外一个进步效率的法方是在可能的情况下,应当尽量把字段设置为NOT NULL,这样在来将行执查询的时候,据数库不用去较比NULL值。

    对于某些本文字段,例如“份省”或者“性别”,我们可以将它们定义为ENUM类型。因为在MySQL中,ENUM类型被作当值数型据数来处置,而值数型据数被处置起来的度速要比本文类型快得多。这样,我们又可以进步据数库的能性。

    2、应用连接(JOIN)来取代子查询(Sub-Queries)

    MySQL从4.1开始持支SQL的子查询。这个术技可以应用SELECT语句来建创一个单列的查询结果,然后把这个结果作为滤过条件用在另一个查询中。例如,我们要将客户基本息信表中没有任何订单的客户删掉除,以可就利用子查询先从售销息信表中将全部收回订单的客户ID出取来,然后将结果传递给主查询,如下所示:

    DELETE FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )

    应用子查询可以一次性的成完很多逻辑上要需多个步调才能成完的SQL操纵,同时也可以防止事务或者表锁死,并且写起来也很易容。但是,有些情况下,子查询可以被更有效率的连接(JOIN).. 替换。例如,设假我们要将全部没有订单记载的用户出取来,可以用面下这个查询成完:

    SELECT * FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )

    如果应用连接(JOIN).. 来成完这个查询作工,度速将会快很多。尤其是当salesinfo表中对CustomerID建有引索的话,能性将会更好,查询如下:

    SELECT * FROM customerinfo LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo. CustomerID WHERE salesinfo.CustomerID IS NULL

    连接(JOIN).. 之所以更有效率一些,是因为 MySQL不要需在内存中建创临时表来成完这个逻辑上的要需两个步调的查询作工。

    3、应用合联(UNION)来取代手动建创的临时表

    MySQL 从 4.0 的本版开始持支 UNION 查询,它可以把要需应用临时表的两条或更多的 SELECT 查询合并的一个查询中。在客户端的查询会话束结的时候,临时表会被主动删除,从而保障据数库整洁、高效。应用 UNION 来建创查询的时候,我们只要需用 UNION作为关键字把多个 SELECT 语句连接起来以可就了,要注意的是全部 SELECT 语句中的字段目数要想同。面下的例子就演示了一个应用 UNION的查询。

    SELECT Name, Phone FROM client UNION SELECT Name, BirthDate FROM author
UNION
SELECT Name, Supplier FROM product

    4、事务

    尽管我们可以应用子查询(Sub-Queries)、连接(JOIN)和合联(UNION)来建创林林总总的查询,但不是全部的据数库操纵都可以只用一条或多数几条SQL语句以可就成完的。更多的时候是要需用到一系列的语句来成完某种作工。但是在种这情况下,当这个语句块中的某一条语句行运错出的时候,整个语句块的操纵就会变得不确定起来。想设一下,要把某个据数同时插入两个相干联的表中,可能会现出这样的情况:第一个表中胜利更新后,据数库忽然现出意外状态,成造第二个表中的操纵没有成完,这样,就会成造据数的不完整,甚至会损坏据数库中的据数。要防止种这情况,就应当应用事务,它的用作是:要么语句块中每条语句都操纵胜利,要么都失败。换句话说,就是可以坚持据数库中据数的一致性和完整性。事物以BEGIN 关键字开始,COMMIT关键字束结。在这之间的一条SQL操纵失败,那么,ROLLBACK命令以可就把据数库恢复到BEGIN开始之前的状态。

    BEGIN;

    INSERT INTO salesinfo SET CustomerID=14;

    UPDATE inventory SET Quantity=11

    WHERE item='book';

    COMMIT;

    事务的另一个重要用作是当多个用户同时应用雷同的据数源时,它可以利用锁定据数库的法方来为用户供提一种安全的问访方法,这样可以保障用户的操纵不被其它的用户所干扰。

    5、锁定表

    尽管事务是维护据数库完整性的一个非常好的法方,但却因为它的独占性,有时会影响据数库的能性,尤其是在很大的应用统系中。由于在事务行执的程过中,据数库将会被锁定,因此其它的用户请求只能临时待等直到该事务束结。如果一个据数库统系只有多数几个用户

    来应用,事务成造的影响不会成为一个太大的问题;但设假有不计其数的用户同时问访一个据数库统系,例如问访一个电子商务网站,就会生产较比严重的应响延迟。

    其实,有些情况下我们可以通过锁定表的法方来得获更好的能性。面下的例子就用锁定表的法方来成完前面一个例子中事务的功能。

    LOCK TABLE inventory WRITE
SELECT Quantity FROM inventory
WHEREItem='book';
...

    每日一道理
哦,妈妈 亲爱的妈妈,您对我的爱比太阳还要炽热,比白雪更为圣洁。在我成长的道路上,您就是女儿夏日里的浓荫,冬天里的炭火,您更是女儿人生路上的一盏明灯。

    UPDATE inventory SET Quantity=11
WHEREItem='book';
UNLOCK TABLES

    这里,我们用一个 SELECT 语句出取初始据数,通过一些算计,用 UPDATE 语句将新值更新到表中。包含有 WRITE 关键字的 LOCK TABLE 语句可以保障在 UNLOCK TABLES 命令被行执之前,不会有其它的问访来对 inventory 停止插入、更新或者删除的操纵。

    6、应用外键

    锁定表的法方可以维护据数的完整性,但是它却不能保障据数的关联性。这个时候我们以可就应用外键。例如,外键可以保障每一条售销记载都指向某一个存在的客户。在这里,外键可以把customerinfo 表中的CustomerID映射到salesinfo表中CustomerID,任何一条没有正当CustomerID的记载都不会被更新或插入到salesinfo中。

    CREATE TABLE customerinfo
(
CustomerID INT NOT NULL ,
PRIMARY KEY ( CustomerID )
) TYPE = INNODB;
CREATE TABLE salesinfo
(
SalesID INT NOT NULL,
CustomerID INT NOT NULL,
PRIMARY KEY(CustomerID, SalesID),
FOREIGN KEY (CustomerID) REFERENCES customerinfo
(CustomerID) ON DELETECASCADE
) TYPE = INNODB;

    注意例子中的参数“ON DELETE CASCADE”。该参数保障当 customerinfo 表中的一条客户记载被删除的时候,salesinfo 表中全部与该客户相干的记载也会被主动删除。如果要在 MySQL 中应用外键,一定要记住在建创表的时候将表的类型定义为事务安全表 InnoDB类型。该类型不是 MySQL 表的默许类型。定义的法方是在 CREATE TABLE 语句中加上 TYPE=INNODB。如例中所示。

    7、应用引索

    引索是进步据数库能性的经常使用法方,它可以令据数库服务器以比没有引索快得多的度速检索特定的行,尤其是在查询语句当中包含有MAX(), MIN()和ORDERBY这些命令的时候,能性进步更为显明。那该对哪些字段建立引索呢?一般说来,引索应建立在那些将用于JOIN, WHERE判断和ORDER BY排序的字段上。尽量不要对据数库中某个含有大批复重的值的字段建立引索。对于一个ENUM类型的字段说来,现出大批复重值是很有可能的情况,例如customerinfo中的“province”.. 字段,在这样的字段上建立引索将不会有什么助帮;相反,还有可能下降据数库的能性。我们在建创表的时候可以同时建创适合的引索,也可以应用ALTER TABLE或CREATE INDEX在后以建创引索。此外,MySQL

    从本版3.23.23开始持支全文引索和搜索。全文引索在MySQL 中是一个FULLTEXT类型引索,但仅能用于MyISAM 类型的表。对于一个大的据数库,将据数装载到一个没有FULLTEXT引索的表中,然后再应用ALTER TABLE或CREATE INDEX建创引索,将是非常快的。但如果将据数装载到一个已经有FULLTEXT引索的表中,行执程过将会非常慢。

    8、优化的查询语句

    绝大多数情况下,应用引索可以进步查询的度速,但如果SQL语句应用不当恰的话,引索将没法挥发它应有的用作。面下是应当注意的几个方面。首先,最好是在雷同类型的字段间停止较比的操纵。在MySQL 3.23版之前,这甚至是一个必须的条件。例如不能将一个建有引索的INT字段和BIGINT字段停止较比;但是作为特别的情况,在CHAR类型的字段和VARCHAR类型字段的字段巨细雷同的时候,可以将它们停止较比。其次,在建有引索的字段上尽量不要应用函数停止操纵。

    例如,在一个DATE类型的字段上应用YEAE()函数时,将会使引索不能挥发应有的用作。所以,面下的两个查询虽然回返的结果一样,但后者要比前者快得多。

    SELECT * FROM order WHERE YEAR(OrderDate)<2001;
SELECT * FROM order WHERE OrderDate<"2001-01-01";

    样同的形情也会发生在对值数型字段停止算计的时候:

    SELECT * FROM inventory WHERE Amount/7<24;
SELECT * FROM inventory WHERE Amount<24*7;

    下面的两个查询也是回返雷同的结果,但前面的查询将比前面的一个快很多。第三,在搜索符字型字段时,我们有时会应用 LIKE 关键字和通配符,种这做法虽然单简,但却也是以牲牺统系能性为价代的。例如面下的查询将会较比表中的每一条记载。

    SELECT * FROM books
WHERE name like "MySQL%"

    但是如果换用面下的查询,回返的结果一样,但度速就要快上很多:

    SELECT * FROM books
WHERE name>="MySQL"and name<"MySQM"

    最后,应当注意防止在查询中让MySQL停止主动类型转换,因为转换程过也会使引索变得不起用作。

       本文并非原创。

文章结束给大家分享下程序员的一些笑话语录: 一程序员告老还乡,想安度晚年,于是决定在书法上有所造诣。省略数字……,准备好文房4宝,挥起毛笔在白纸上郑重的写下:Hello World

原文地址:https://www.cnblogs.com/xinyuyuanm/p/3061767.html