精华内容
下载资源
问答
  • mysql 数据库优化

    万次阅读 2021-06-07 23:39:00
    mysql 优化配置 [client] port=3306 socket=/var/lib/mysql/mysql.sock [mysqld] port=3306 socket=/var/lib/mysql/mysql.sock datadir=/data/db/mysql skip-external-locking character-set-server=ut

    #创建mysql 存储目录

    mkdir /data/db/mysql -p
    chown mysql.mysql /data/db/mysql/
    

    mysql 优化配置

    [client]
    port=3306
    socket=/var/lib/mysql/mysql.sock
    [mysqld]
    port=3306
    socket=/var/lib/mysql/mysql.sock
    datadir=/data/db/mysql
    skip-external-locking
    character-set-server=utf8
    slow_query_log
    slow_query_log_file=/var/log/mysql/slowquery.log
    long_query_time=2
    log-error=/var/log/mysql/log-error.log
    skip-name-resolve
    max_connections=5000
    back_log=300
    table-cache=4096
    max_allowed_packet=32M
    max-heap-table-size=128M
    key_buffer_size=128M
    sort-buffer-size=16M
    join-buffer-size=16M
    net_buffer_length=8K
    read_buffer_size=256K
    read_rnd_buffer_size=512K
    myisam_sort_buffer_size=8M
    thread-cache-size=16
    thread-concurrency=24
    query-cache-size=4096M
    query-cache-limit=4M
    tmp-table-size=128M
    log_warnings
    innodb_file_per_table=1
    innodb_file_io_threads=4
    innodb_open_files=2048
    innodb_buffer_pool_size=4G
    innodb_additional_mem_pool=16M
    innodb_thread_concurrency=16
    innodb_max_dirty_pages_pct=90
    log-bin=mysql-bin
    binlog_format=mixed
    server-id=1
    [mysqldump]
    quick
    max_allowed_packet=16M
    [mysql]
    no-auto-rehash
    [myisamchk]
    key_buffer_size=20M
    sort_buffer_size=20M
    read_buffer=2M
    write_buffer=2M
    [mysqlhotcopy]
    interactive-timeout
    
    展开全文
  • MySQL数据库优化的八种方式(经典必看)

    万次阅读 多人点赞 2019-03-13 15:48:28
    MySQL数据库优化的八种方式(经典必看) 引言: 关于数据库优化,网上有不少资料和方法,但是不少质量参差不齐,有些总结的不够到位,内容冗杂 偶尔发现了这篇文章,总结得很经典,文章流量也很大,所以拿...

    MySQL数据库优化的八种方式(经典必看)

    引言:

     
    1. 关于数据库优化,网上有不少资料和方法,但是不少质量参差不齐,有些总结的不够到位,内容冗杂

    2. 偶尔发现了这篇文章,总结得很经典,文章流量也很大,所以拿到自己的总结文集中,积累优质文章,提升个人能力,希望对大家今后开发中也有帮助

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

    MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。

    例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGIN来定义整型字段。

    另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOTNULL,这样在将来执行查询的时候,数据库不用去比较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  salesinfo  ON   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   WHERE Item='book';
    
    ...
    
    UPDATE   inventory   SET   Quantity=11   WHERE  Item='book';UNLOCKTABLES
    

     

    这里,我们用一个select语句取出初始数据,通过一些计算,用update语句将新值更新到表中。包含有WRITE关键字的LOCKTABLE语句可以保证在UNLOCKTABLES命令被执行之前,不会有其它的访问来对inventory进行插入、更新或者删除的操作。

    6、使用外键

    锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。

    例如,外键可以保证每一条销售记录都指向某一个存在的客户。在这里,外键可以把customerinfo表中的CustomerID映射到salesinfo表中CustomerID,任何一条没有合法CustomerID的记录都不会被更新或插入到salesinfo中。

    CREATE  TABLE   customerinfo( customerid   int primary key) engine = innodb;
    
    CREATE  TABLE   salesinfo( salesid int not null,
    customerid  int not null, 
    primary key(customerid,salesid),
    foreign key(customerid)  
    references  customerinfo(customerid) on delete cascade)engine = innodb;
    
    

     

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

    7、使用索引

    索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,性能提高更为明显。

    那该对哪些字段建立索引呢?

    一般说来,索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个ENUM类型的字段来说,出现大量重复值是很有可能的情况

    例如customerinfo中的“province”..字段,在这样的字段上建立索引将不会有什么帮助;相反,还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引,也可以使用ALTERTABLE或CREATEINDEX在以后创建索引。此外,MySQL从版本3.23.23开始支持全文索引和搜索。全文索引在MySQL中是一个FULLTEXT类型索引,但仅能用于MyISAM类型的表。对于一个大的数据库,将数据装载到一个没有FULLTEXT索引的表中,然后再使用ALTERTABLE或CREATEINDEX创建索引,将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中,执行过程将会非常慢。

    8、优化的查询语句

    绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。

    下面是应该注意的几个方面。

    • 首先,最好是在相同类型的字段间进行比较的操作。

      在MySQL3.23版之前,这甚至是一个必须的条件。例如不能将一个建有索引的INT字段和BIGINT字段进行比较;但是作为特殊的情况,在CHAR类型的字段和VARCHAR类型字段的字段大小相同的时候,可以将它们进行比较。

    • 其次,在建有索引的字段上尽量不要使用函数进行操作。

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

    • 第三,在搜索字符型字段时,我们有时会使用LIKE关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。

    例如下面的查询将会比较表中的每一条记录。

    
    SELECT  *  FROM  books  WHERE  name  like   "MySQL%"

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

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

     

    最后,应该注意避免在查询中让MySQL进行自动类型转换,因为转换过程也会使索引变得不起作用。

    优化Mysql数据库的8个方法

    本文通过8个方法优化Mysql数据库:创建索引、复合索引、索引不会包含有NULL值的列、使用短索引、排序的索引问题、like语句操作、不要在列上进行运算、不使用NOT IN和<>操作

    1、创建索引
    对于查询占主要的应用来说,索引显得尤为重要。很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致。如果不加索引的话,那么查找任何哪怕只是一条特定的数据都会进行一次全表扫描,如果一张表的数据量很大而符合条件的结果又很少,那么不加索引会引起致命的性能下降。但是也不是什么情况都非得建索引不可,比如性别可能就只有两个值,建索引不仅没什么优势,还会影响到更新速度,这被称为过度索引。
    2、复合索引
    比如有一条语句是这样的:select * from users where area='beijing' and age=22;
    如果我们是在area和age上分别创建单个索引的话,由于mysql查询每次只能使用一个索引,所以虽然这样已经相对不做索引时全表扫描提高了很多效率,但是如果在area、age两列上创建复合索引的话将带来更高的效率。如果我们创建了(area, age, salary)的复合索引,那么其实相当于创建了(area,age,salary)、(area,age)、(area)三个索引,这被称为最佳左前缀特性。因此我们在创建复合索引时应该将最常用作限制条件的列放在最左边,依次递减。
    3、索引不会包含有NULL值的列
    只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。
    4、使用短索引
    对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的 列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
    5、排序的索引问题
    mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。
    6、like语句操作
    一般情况下不鼓励使用like操作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。
    7、不要在列上进行运算
    select * from users where YEAR(adddate)<2007;
    将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成
    select * from users where adddate<‘2007-01-01';
    8、不使用NOT IN和<>操作
    NOT IN和<>操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替,id<>3则可使用id>3 or id<3来代替。

    数据库SQL优化大总结之 百万级数据库优化方案

    网上关于SQL优化的教程很多,但是比较杂乱。近日有空整理了一下,写出来跟大家分享一下,其中有错误和不足的地方,还请大家纠正补充。

    这篇文章我花费了大量的时间查找资料、修改、排版,希望大家阅读之后,感觉好的话推荐给更多的人,让更多的人看到、纠正以及补充。

    1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。


    2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

    select id from t where num is null

    最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.

    备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。

    不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。


    可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

    select id from t where num = 0


    3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。

    4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:

    select id from t where num=10 or Name = 'admin'

    可以这样查询:

    select id from t where num = 10
    union all
    select id from t where Name = 'admin'


    5.in 和 not in 也要慎用,否则会导致全表扫描,如:

    select id from t where num in(1,2,3)

    对于连续的数值,能用 between 就不要用 in 了:

    select id from t where num between 1 and 3

    很多时候用 exists 代替 in 是一个好的选择:

    select num from a where num in(select num from b)

    用下面的语句替换:

    select num from a where exists(select 1 from b where num=a.num)

    6.下面的查询也将导致全表扫描:

    select id from t where name like ‘%abc%’

    若要提高效率,可以考虑全文检索。

    7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然 而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

    select id from t where num = @num

    可以改为强制查询使用索引:

    select id from t with(index(索引名)) where num = @num

    .应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

    select id from t where num/2 = 100

    应改为:

    select id from t where num = 100*2


    9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

    select id from t where substring(name,1,3) = ’abc’       -–name以abc开头的id
    select id from t where datediff(day,createdate,’2005-11-30′) = 0    -–‘2005-11-30’    --生成的id

    应改为:

    select id from t where name like 'abc%'
    select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'


    10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

    11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

    12.不要写一些没有意义的查询,如需要生成一个空表结构:

    select col1,col2 into #t from t where 1=0

    这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
    create table #t(…)

    13.Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。

    14.对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。

    15.select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。


    16.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。

    17.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

    18.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

    19.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

    20.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

    21.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

    22. 避免频繁创建和删除临时表,以减少系统表资源的消耗。临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件, 最好使用导出表。

    23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

    24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

    25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

    26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

    27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时 间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

    28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

    29.尽量避免大事务操作,提高系统并发能力。

    30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

    实际案例分析:拆分大的 DELETE 或INSERT 语句,批量提交SQL语句
      如果你需要在一个在线的网站上去执行一个大的 DELETE 或 INSERT 查询,你需要非常小心,要避免你的操作让你的整个网站停止相应。因为这两个操作是会锁表的,表一锁住了,别的操作都进不来了。
      Apache 会有很多的子进程或线程。所以,其工作起来相当有效率,而我们的服务器也不希望有太多的子进程,线程和数据库链接,这是极大的占服务器资源的事情,尤其是内存。
      如果你把你的表锁上一段时间,比如30秒钟,那么对于一个有很高访问量的站点来说,这30秒所积累的访问进程/线程,数据库链接,打开的文件数,可能不仅仅会让你的WEB服务崩溃,还可能会让你的整台服务器马上挂了。
      所以,如果你有一个大的处理,你一定把其拆分,使用 LIMIT oracle(rownum),sqlserver(top)条件是一个好的方法。下面是一个mysql示例:

    while(1){
    
       //每次只做1000条
    
       mysql_query(“delete from logs where log_date <= ’2012-11-01’ limit 1000”);
    
       if(mysql_affected_rows() == 0){
    
         //删除完成,退出!
         break;
      }
    
    //每次暂停一段时间,释放表让其他进程/线程访问。
    usleep(50000)
    
    }

    好了,到这里就写完了。我知道还有很多没有写到的,还请大家补充。后面有空会介绍一些SQL优化工具给大家。让我们一起学习,一起进步吧!

    运维角度浅谈MySQL数据库优化

     一个成熟的数据库架构并不是一开始设计就具备高可用、高伸缩等特性的,它是随着用户量的增加,基础架构才逐渐完善。这篇博文主要谈MySQL数据库发展周期中所面临的问题及优化方案,暂且抛开前端应用不说,大致分为以下五个阶段:

    1、数据库表设计

      项目立项后,开发部根据产品部需求开发项目,开发工程师工作其中一部分就是对表结构设计。对于数据库来说,这点很重要,如果设计不当,会直接影响访问速度和用户体验。影响的因素很多,比如慢查询、低效的查询语句、没有适当建立索引、数据库堵塞(死锁)等。当然,有测试工程师的团队,会做压力测试,找bug。对于没有测试工程师的团队来说,大多数开发工程师初期不会太多考虑数据库设计是否合理,而是尽快完成功能实现和交付,等项目有一定访问量后,隐藏的问题就会暴露,这时再去修改就不是这么容易的事了。

    2、数据库部署

      该运维工程师出场了,项目初期访问量不会很大,所以单台部署足以应对在1500左右的QPS(每秒查询率)。考虑到高可用性,可采用MySQL主从复制+Keepalived做双击热备,常见集群软件有Keepalived、Heartbeat。

    双机热备博文:http://lizhenliang.blog.51cto.com/7876557/1362313

    3、数据库性能优化

      如果将MySQL部署到普通的X86服务器上,在不经过任何优化情况下,MySQL理论值正常可以处理2000左右QPS,经过优化后,有可能会提升到2500左右QPS,否则,访问量当达到1500左右并发连接时,数据库处理性能就会变慢,而且硬件资源还很富裕,这时就该考虑软件问题了。那么怎样让数据库最大化发挥性能呢?一方面可以单台运行多个MySQL实例让服务器性能发挥到最大化,另一方面是对数据库进行优化,往往操作系统和数据库默认配置都比较保守,会对数据库发挥有一定限制,可对这些配置进行适当的调整,尽可能的处理更多连接数。

    具体优化有以下三个层面:

      3.1 数据库配置优化

      MySQL常用有两种存储引擎,一个是MyISAM,不支持事务处理,读性能处理快,表级别锁。另一个是InnoDB,支持事务处理(ACID),设计目标是为处理大容量数据发挥最大化性能,行级别锁。

      表锁:开销小,锁定粒度大,发生死锁概率高,相对并发也低。

      行锁:开销大,锁定粒度小,发生死锁概率低,相对并发也高。

      为什么会出现表锁和行锁呢?主要是为了保证数据的完整性,举个例子,一个用户在操作一张表,其他用户也想操作这张表,那么就要等第一个用户操作完,其他用户才能操作,表锁和行锁就是这个作用。否则多个用户同时操作一张表,肯定会数据产生冲突或者异常。

      根据以上看来,使用InnoDB存储引擎是最好的选择,也是MySQL5.5以后版本中默认存储引擎。每个存储引擎相关联参数比较多,以下列出主要影响数据库性能的参数。

      公共参数默认值:

    1

    2

    3

    4

    5

    6

    max_connections = 151

    #同时处理最大连接数,推荐设置最大连接数是上限连接数的80%左右   

    sort_buffer_size = 2M

    #查询排序时缓冲区大小,只对order by和group by起作用,可增大此值为16M

    open_files_limit = 1024 

    #打开文件数限制,如果show global status like 'open_files'查看的值等于或者大于open_files_limit值时,程序会无法连接数据库或卡死

      MyISAM参数默认值:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    key_buffer_size = 16M

    #索引缓存区大小,一般设置物理内存的30-40%

    read_buffer_size = 128K  

    #读操作缓冲区大小,推荐设置16M或32M

    query_cache_type = ON

    #打开查询缓存功能

    query_cache_limit = 1M  

    #查询缓存限制,只有1M以下查询结果才会被缓存,以免结果数据较大把缓存池覆盖

    query_cache_size = 16M  

    #查看缓冲区大小,用于缓存SELECT查询结果,下一次有同样SELECT查询将直接从缓存池返回结果,可适当成倍增加此值

      InnoDB参数默认值:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    innodb_buffer_pool_size = 128M

    #索引和数据缓冲区大小,一般设置物理内存的60%-70%

    innodb_buffer_pool_instances = 1    

    #缓冲池实例个数,推荐设置4个或8个

    innodb_flush_log_at_trx_commit = 1  

    #关键参数,0代表大约每秒写入到日志并同步到磁盘,数据库故障会丢失1秒左右事务数据。1为每执行一条SQL后写入到日志并同步到磁盘,I/O开销大,执行完SQL要等待日志读写,效率低。2代表只把日志写入到系统缓存区,再每秒同步到磁盘,效率很高,如果服务器故障,才会丢失事务数据。对数据安全性要求不是很高的推荐设置2,性能高,修改后效果明显。

    innodb_file_per_table = OFF  

    #默认是共享表空间,共享表空间idbdata文件不断增大,影响一定的I/O性能。推荐开启独立表空间模式,每个表的索引和数据都存在自己独立的表空间中,可以实现单表在不同数据库中移动。

    innodb_log_buffer_size = 8M  

    #日志缓冲区大小,由于日志最长每秒钟刷新一次,所以一般不用超过16M

      3.2 系统内核优化

      大多数MySQL都部署在linux系统上,所以操作系统的一些参数也会影响到MySQL性能,以下对linux内核进行适当优化。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    net.ipv4.tcp_fin_timeout = 30

    #TIME_WAIT超时时间,默认是60s

    net.ipv4.tcp_tw_reuse = 1    

    #1表示开启复用,允许TIME_WAIT socket重新用于新的TCP连接,0表示关闭

    net.ipv4.tcp_tw_recycle = 1  

    #1表示开启TIME_WAIT socket快速回收,0表示关闭

    net.ipv4.tcp_max_tw_buckets = 4096   

    #系统保持TIME_WAIT socket最大数量,如果超出这个数,系统将随机清除一些TIME_WAIT并打印警告信息

    net.ipv4.tcp_max_syn_backlog = 4096

    #进入SYN队列最大长度,加大队列长度可容纳更多的等待连接

      在linux系统中,如果进程打开的文件句柄数量超过系统默认值1024,就会提示“too many files open”信息,所以要调整打开文件句柄限制。

    1

    2

    3

    4

    # vi /etc/security/limits.conf  #加入以下配置,*代表所有用户,也可以指定用户,重启系统生效

    * soft nofile 65535

    * hard nofile 65535

    # ulimit -SHn 65535   #立刻生效

      3.3 硬件配置

      加大物理内存,提高文件系统性能。linux内核会从内存中分配出缓存区(系统缓存和数据缓存)来存放热数据,通过文件系统延迟写入机制,等满足条件时(如缓存区大小到达一定百分比或者执行sync命令)才会同步到磁盘。也就是说物理内存越大,分配缓存区越大,缓存数据越多。当然,服务器故障会丢失一定的缓存数据。

      SSD硬盘代替SAS硬盘,将RAID级别调整为RAID1+0,相对于RAID1和RAID5有更好的读写性能(IOPS),毕竟数据库的压力主要来自磁盘I/O方面。

    4、数据库架构扩展

      随着业务量越来越大,单台数据库服务器性能已无法满足业务需求,该考虑加机器了,该做集群了~~~。主要思想是分解单台数据库负载,突破磁盘I/O性能,热数据存放缓存中,降低磁盘I/O访问频率。

      4.1 主从复制与读写分离

      因为生产环境中,数据库大多都是读操作,所以部署一主多从架构,主数据库负责写操作,并做双击热备,多台从数据库做负载均衡,负责读操作,主流的负载均衡器有LVS、HAProxy、Nginx。

      怎么来实现读写分离呢?大多数企业是在代码层面实现读写分离,效率比较高。另一个种方式通过代理程序实现读写分离,企业中应用较少,常见代理程序有MySQL Proxy、Amoeba。在这样数据库集群架构中,大大增加数据库高并发能力,解决单台性能瓶颈问题。如果从数据库一台从库能处理2000 QPS,那么5台就能处理1w QPS,数据库横向扩展性也很容易。

      有时,面对大量写操作的应用时,单台写性能达不到业务需求。如果做双主,就会遇到数据库数据不一致现象,产生这个原因是在应用程序不同的用户会有可能操作两台数据库,同时的更新操作造成两台数据库数据库数据发生冲突或者不一致。在单库时MySQL利用存储引擎机制表锁和行锁来保证数据完整性,怎样在多台主库时解决这个问题呢?有一套基于perl语言开发的主从复制管理工具,叫MySQL-MMM(Master-Master replication managerfor Mysql,Mysql主主复制管理器),这个工具最大的优点是在同一时间只提供一台数据库写操作,有效保证数据一致性。

      主从复制博文:http://lizhenliang.blog.51cto.com/7876557/1290431

      读写分离博文:http://lizhenliang.blog.51cto.com/7876557/1305083

     MySQL-MMM博文:http://lizhenliang.blog.51cto.com/7876557/1354576

      4.2 增加缓存

      给数据库增加缓存系统,把热数据缓存到内存中,如果缓存中有要请求的数据就不再去数据库中返回结果,提高读性能。缓存实现有本地缓存和分布式缓存,本地缓存是将数据缓存到本地服务器内存中或者文件中。分布式缓存可以缓存海量数据,扩展性好,主流的分布式缓存系统有memcached、redis,memcached性能稳定,数据缓存在内存中,速度很快,QPS可达8w左右。如果想数据持久化就选择用redis,性能不低于memcached。

      工作过程:

      

    https://img-blog.csdnimg.cn/img_convert/a95e42d046f9f423a98c415be9e700e6.png

      4.3 分库

      分库是根据业务不同把相关的表切分到不同的数据库中,比如web、bbs、blog等库。如果业务量很大,还可将切分后的库做主从架构,进一步避免单个库压力过大。

      4.4 分表

      数据量的日剧增加,数据库中某个表有几百万条数据,导致查询和插入耗时太长,怎么能解决单表压力呢?你就该考虑是否把这个表拆分成多个小表,来减轻单个表的压力,提高处理效率,此方式称为分表。

      分表技术比较麻烦,要修改程序代码里的SQL语句,还要手动去创建其他表,也可以用merge存储引擎实现分表,相对简单许多。分表后,程序是对一个总表进行操作,这个总表不存放数据,只有一些分表的关系,以及更新数据的方式,总表会根据不同的查询,将压力分到不同的小表上,因此提高并发能力和磁盘I/O性能。

      分表分为垂直拆分和水平拆分:

      垂直拆分:把原来的一个很多字段的表拆分多个表,解决表的宽度问题。你可以把不常用的字段单独放到一个表中,也可以把大字段独立放一个表中,或者把关联密切的字段放一个表中。

      水平拆分:把原来一个表拆分成多个表,每个表的结构都一样,解决单表数据量大的问题。

      4.5 分区

      分区就是把一张表的数据根据表结构中的字段(如range、list、hash等)分成多个区块,这些区块可以在一个磁盘上,也可以在不同的磁盘上,分区后,表面上还是一张表,但数据散列在多个位置,这样一来,多块硬盘同时处理不同的请求,从而提高磁盘I/O读写性能,实现比较简单。

    注:增加缓存、分库、分表和分区主要由程序猿来实现。

    5、数据库维护

      数据库维护是运维工程师或者DBA主要工作,包括性能监控、性能分析、性能调优、数据库备份和恢复等。

      5.1 性能状态关键指标

      QPS,Queries Per Second:每秒查询数,一台数据库每秒能够处理的查询次数

      TPS,Transactions Per Second:每秒处理事务数

      通过show status查看运行状态,会有300多条状态信息记录,其中有几个值帮可以我们计算出QPS和TPS,如下:

      Uptime:服务器已经运行的实际,单位秒

      Questions:已经发送给数据库查询数

      Com_select:查询次数,实际操作数据库的

      Com_insert:插入次数

      Com_delete:删除次数

      Com_update:更新次数

      Com_commit:事务次数

      Com_rollback:回滚次数

      那么,计算方法来了,基于Questions计算出QPS:

    1

    2

      mysql> show global status like 'Questions';

      mysql> show global status like 'Uptime';

      QPS = Questions / Uptime

      基于Com_commit和Com_rollback计算出TPS:

    1

    2

    3

      mysql> show global status like 'Com_commit';

      mysql> show global status like 'Com_rollback';

      mysql> show global status like 'Uptime';

      TPS = (Com_commit + Com_rollback) / Uptime

      另一计算方式:基于Com_select、Com_insert、Com_delete、Com_update计算出QPS

    1

      mysql> show global status where Variable_name in('com_select','com_insert','com_delete','com_update');

      等待1秒再执行,获取间隔差值,第二次每个变量值减去第一次对应的变量值,就是QPS

      TPS计算方法:

    1

      mysql> show global status where Variable_name in('com_insert','com_delete','com_update');

      计算TPS,就不算查询操作了,计算出插入、删除、更新四个值即可。

      经网友对这两个计算方式的测试得出,当数据库中myisam表比较多时,使用Questions计算比较准确。当数据库中innodb表比较多时,则以Com_*计算比较准确。

      5.2 开启慢查询日志

      MySQL开启慢查询日志,分析出哪条SQL语句比较慢,使用set设置变量,重启服务失效,可以在my.cnf添加参数永久生效。

    1

    2

    3

    4

    mysql> set global slow-query-log=on  #开启慢查询功能

    mysql> set global slow_query_log_file='/var/log/mysql/mysql-slow.log';  #指定慢查询日志文件位置

    mysql> set global log_queries_not_using_indexes=on;   #记录没有使用索引的查询

    mysql> set global long_query_time=1;   #只记录处理时间1s以上的慢查询

      分析慢查询日志,可以使用MySQL自带的mysqldumpslow工具,分析的日志较为简单。

      # mysqldumpslow -t 3 /var/log/mysql/mysql-slow.log    #查看最慢的前三个查询

      也可以使用percona公司的pt-query-digest工具,日志分析功能全面,可分析slow log、binlog、general log。

      分析慢查询日志:pt-query-digest /var/log/mysql/mysql-slow.log

      分析binlog日志:mysqlbinlog mysql-bin.000001 >mysql-bin.000001.sql 

      pt-query-digest --type=binlog mysql-bin.000001.sql 

      分析普通日志:pt-query-digest --type=genlog localhost.log

      5.3 数据库备份

      备份数据库是最基本的工作,也是最重要的,否则后果很严重,你懂得!但由于数据库比较大,上百G,往往备份都很耗费时间,所以就该选择一个效率高的备份策略,对于数据量大的数据库,一般都采用增量备份。常用的备份工具有mysqldump、mysqlhotcopy、xtrabackup等,mysqldump比较适用于小的数据库,因为是逻辑备份,所以备份和恢复耗时都比较长。mysqlhotcopy和xtrabackup是物理备份,备份和恢复速度快,不影响数据库服务情况下进行热拷贝,建议使用xtrabackup,支持增量备份。

      Xtrabackup备份工具使用博文:http://lizhenliang.blog.51cto.com/7876557/1612800

      5.4 数据库修复

      有时候MySQL服务器突然断电、异常关闭,会导致表损坏,无法读取表数据。这时就可以用到MySQL自带的两个工具进行修复,myisamchk和mysqlcheck。

      myisamchk:只能修复myisam表,需要停止数据库

      常用参数:

      -f --force    强制修复,覆盖老的临时文件,一般不使用

      -r --recover  恢复模式

      -q --quik     快速恢复

      -a --analyze  分析表

      -o --safe-recover 老的恢复模式,如果-r无法修复,可以使用此参数试试

      -F --fast     只检查没有正常关闭的表

      快速修复weibo数据库:

      # cd /var/lib/mysql/weibo 

      # myisamchk -r -q *.MYI

      mysqlcheck:myisam和innodb表都可以用,不需要停止数据库,如修复单个表,可在数据库后面添加表名,以空格分割

      常用参数:

      -a  --all-databases  检查所有的库

      -r  --repair   修复表

      -c  --check    检查表,默认选项

      -a  --analyze  分析表

      -o  --optimize 优化表

      -q  --quik   最快检查或修复表

      -F  --fast   只检查没有正常关闭的表

      快速修复weibo数据库:

      mysqlcheck -r -q -uroot -p123 weibo 

      5.5 另外,查看CPU和I/O性能方法

      #查看CPU性能

    https://img-blog.csdnimg.cn/img_convert/432dafa8118f9bd2f40b50b84e105de8.png

      #参数-P是显示CPU数,ALL为所有,也可以只显示第几颗CPU

    https://img-blog.csdnimg.cn/img_convert/47054452e21ad148ae0bedc11ca2a69b.png

      #查看I/O性能

    https://img-blog.csdnimg.cn/img_convert/02769fb2a6258573976dedb3f00f0816.png

      #参数-m是以M单位显示,默认K

      #%util:当达到100%时,说明I/O很忙。

      #await:请求在队列中等待时间,直接影响read时间。

      I/O极限:IOPS(r/s+w/s),一般RAID0/10在1200左右。(IOPS,每秒进行读写(I/O)操作次数)

      I/O带宽:在顺序读写模式下SAS硬盘理论值在300M/s左右,SSD硬盘理论值在600M/s左右。

    展开全文
  • 面试不再尬聊的Mysql数据库优化方案

    万次阅读 多人点赞 2020-03-23 11:41:10
    数据库优化是一个老生常谈的问题,刚入门的小白或者工作N年的光头对这个问题应该都不陌生,你要面试一个中高级工程师那么他就想"哥俩好"一样那么粘,面试官肯定会问这个问题,这篇文章我们就和它哥俩好!而且这个...

    点赞多大胆,就有多大产!有支持才有动力!将技术分享给每一个技术使用者和爱好者!

    干货满满,摆好姿势,点赞发车!

     前言

    数据库优化是一个老生常谈的问题,刚入门的小白或者工作N年的光头对这个问题应该都不陌生,你要面试一个中高级工程师那么他就想"哥俩好"一样那么粘,面试官肯定会问这个问题,这篇文章我们就和它哥俩好!而且这个问题就是一个送分题,数据库的优化方案基本就是那些,答案也都是固定的,大家只要好好准备这个问题就不会住你,可以在面试中安排面试官,不然就被面试官安排!话不多说下边就针对数据库优化展开讲!

    相关文章

    《MySQL索引从零上手使用》

    《MySQL索引数据结构,看看什么是B+树吧》

    《基于MyCat实现MySQL读写分离》

    《基于MyCat实现MySQL数据拆分》

    面试开始

    小伙子看你简历上写了Mysql,数据库优化了解吗?

    摸摸头之后笑着说数据库优化不是很了解嘿嘿~~~,这时和蔼的面试官头上出现了一抹红!

    如果这时你正好想到了我这篇文章,那么你就会说数据库优化方面我还是很有研究的,请您听我慢慢道来......

    首先

    面试官我想解释一下为什么做数据库优化(这个你心里知道就好了,面试的时候就不要说了)

    • 系统的数据都从数据库上来,数据库的吞吐量和速度一定程度决定系统的并发和响应速度
    • 系统运行与数据量成正比,数据读处理尤其是查询自然就慢
    • Mysql数据库的数据最终在磁盘上持久化存储,读写不如Redis等这些内存数据库

    其次

    面试官大人我想说一下数据库优化一般从以下几个方面来:

    • 数据库设计:数据表设计遵循三范式,使用合适的数据类型,使用合适的存储引擎
    • 适当创建索引
    • 数据库扩展:数据库的分表分库,读写分离等
    • SQL语句优化等

    接下来我们一一说明解释

    数据库设计

    数据库设计3范式

    数据库设计范式如果要满足N范式必须要先满足N-1范式

    第一范式1NF:字段原子性

    第一范式简单的说就是表中的字段是最小不可再分的,我们下边举个例子,我们看到以下一张用户表。里边的字段是不可再分的,这样就符合第一范式的原子性,可能有些朋友会疑问,这个地址还可以分成省份、城市、区/县三个字段,是的!如果是一个电商项目它需要再分,那么就不符合第一范式,所以具体还是看项目的需求,没有固定标准,在项目需求中它的设计已不可再分那么就符合第一范式!

    第二范式2NF: 消除对主键的部分依赖

    2NF的使用是需要满足1NF为前提,在表中添加一个业务字段,而主键不用来做业务处理,比如我们的商品表有商品id,商品id为商品的主键,但是需要创建一个商品编号列来专门处理业务,因为id太敏感,我们处理业务都是用商品编号来处理,比如展示商品时展示编号等等!

    第三范式3NF:在2NF的基础上添加外键

    3NF的使用必须满足2NF,要求表中的每一列只与主键直接相关而不是间接相关,(表中的每一列只能依赖于主键),比如下面的例子,订单表中有客户相关信息,在分离出客户表之后,订单表中只需要有一个用户id即可(外键),而不能有其他的客户信息。因为其他的客户信息直接关联于用户id,而不是直接与订单id直接相关。如下图所示:

    分离之后:

    三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求>性能>表结构。所以不能一味的去追求范式建立数据库!需求才是粑粑

    数据类型

    尽量使用可以正确存储数据的最小数据类型

    更小的数据类型意味着更快,占用更少的磁盘,内存、缓存和处理时间

    尽量使用整型表示字符串

    因为字符集和校对规则,使处理字符比整型更复杂,比如:我们使用数据库内置的datetime类型存储时间而不是字符类型,我们使用整型存储ip而不是直接将ip字符串存到数据库中

    尽可能使用not null

    这个值是很烦人的,建字段时请尽量指定是否非空,NULL使得索引,统计,比较都变得更复杂,而且索引尽量不要创建到可以为null的字段上

    字符串类型

    VARCHAR是可变长字符串

    比定长字符串(CHAR)更节省空间,仅使用必要的空间另外VARCHAR需要额外字节记录字符串长度(不同情况需要字节数不同)

    CHAR类型是定长字符串

    开发中基本很少用(一些公司甚至基本上不考虑这种类型了),注意:字符串长度定义不是字节数,是字符数

    日期和时间类型

    datetime

    使用8字节存储空间,保存从1001年到9999年的秒数。与时区无关,默认情况下,Mysql以一种可排序的格式显示它的值,例如:"2018-10-14 22:30:08"

    timestamp

    只使用4字节存储,保存1970年1月1日午夜以来的秒数,依赖于系统时区,和UNIX时间戳相同,转换函数分别为FROM_UNIXTIME()和UNIX_TIMESTAMP(),可以设置根据当前时间戳更新,比如我们熟悉的update_time字段

    整数类型

    UNSIGNED

    属性表示不允许负值,可以使得正数的上限提高一倍,比如tinyint+unsigned可以使原本的-128~127的范围变为0~255

    tinyint

    我们一般用它存储状态值而不要用int,如果是Boolean类型,那么tinyint(1)当值为1和0时,查询结果自动转为true和false,条件参数相应的也可以直接传入true和false即可

    INT(11)

    不会限制值的范围,只是规定了一些客户端工具用来显示的字符的个数,所以对于存储和计算来说INT(11)和INT(1)相同

    IP地址

    实际上是32位无符号整数,用INT存储,Mysql提供转换函数为INET_ATON()和INET_NTOA()

    小数

    decimal不会损失精度,存储空间会随数据的增大而增大。double占用固定空间,较大数的存储会损失精度,通常存金额用decimal(11,2),这表示整数部分和小数部分分别为9位和2位注意!,当然可以根据具体的金额大小选择长度,注意这时候对应的java中用BigDecimal类来处理运算时要仔细,因为加减法和比较跟平常不一样

    存储引擎

    介绍

    数据库存储引擎是数据库底层组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据操作。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎还可以获得特定的功能。我们可以通过SHOW ENGINES;

    InnoDB存储引擎

    InnoDB越做越好从MySQL5.5版本之后,MySQL的默认内置存储引擎已经是InnoDB,主要特点有

    1. 容灾恢复性比较好
    2. 支持事务,默认事务隔离界别为可重复读
    3. 使用的锁粒度为行锁,可以支持更高的并发
    4. 支持外键
    5. 配合一些热备工具可以支持在线热备份
    6. 在InnoDB中存在着缓冲管理,通过缓冲池,将索引和数据全部缓存起来,加快查询的速度
    7. 对于InnoDB类型的表,其数据的物理组织形式是聚簇表。所有的数据按照主键来组织。根据主键进行排序,数据和索引放在一块,都位于B+数的叶子节点上

    MyISAM存储引擎

    在5.5版本之前,MyISAM是MySQL的默认存储引擎,该存储引擎并发性差,不支持事务,所以使用场景比较少,主要特点有

    1. 不支持事务
    2. 不支持外键,如果强行增加外键,不会提示错误,只是外键不其作用
    3. 对数据的查询缓存只会缓存索引,不会像InnoDB一样缓存数据,而且是利用操作系统本身的缓存
    4. 默认的锁粒度为表级锁,所以并发度很差,加锁快,锁冲突较少,所以不太容易发生死锁
    5. 支持全文索引(MySQL5.6之后,InnoDB存储引擎也对全文索引做了支持),但是MySQL的全文索引基本不会使用,对于全文索引,现在有其他成熟的解决方案,比如:ElasticSearch,Solr,Sphinx等
    6. 数据库所在主机如果宕机,MyISAM的数据文件容易损坏,而且难恢复

    MEMORY存储引擎

    将数据存在内存中,和市场上的Redis,memcached等思想类似,为了提高数据的访问速度,主要特点有

    1. 支持的数据类型有限制,不支持TEXT和BLOB类型,对于字符串类型的数据,只支持固定长度的行,VARCHAR会被自动存储为CHAR类型
    2. 支持的锁粒度为表级锁。所以,在访问量比较大时,表级锁会成为MEMORY存储引擎的瓶颈
    3. 由于数据是存放在内存中,所以在服务器重启之后,所有数据都会丢失
    4. 查询的时候,如果有用到临时表,而且临时表中有BLOB,TEXT类型的字段,那么这个临时表就会转化为MyISAM类型的表,性能会急剧降低

    ARCHIVE存储引擎

    ARCHIVE存储引擎适合的场景有限,由于其支持压缩,故主要是用来做日志,流水等数据的归档,主要特点有

    1. 支持Zlib压缩,数据在插入表之前,会先被压缩
    2. 仅支持SELECT和INSERT操作,存入的数据就只能查询,不能做修改和删除;
    3. 只支持自增键上的索引,不支持其他索引

    CSV存储引擎

    数据中转试用,主要特点有

    1. 其数据格式为.csv格式的文本,可以直接编辑保存
    2. 导入导出比较方便,可以将某个表中的数据直接导出为csv,试用Excel办公软件打开

    选择依据

    如果没有特殊需求默认使用InnoDB引擎即可

    MyISAM:以读写插入为主的应用程序,比如博客系统、新闻门户网站。

    Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键保证数据完整性。比如OA自动化办公系统

    索引

    已为客官备好,轻点哦《这小伙子把MySQL索引使用讲的真明白,真好,快来戳他》

    索引数据结构在这在这《搞懂MySQL数据库索引数据结构这一篇足够从此不再萌萌哒》

    MySQL读写分离

    点一下就会《看了这篇文章觉得MySQL读写分离这么简单》

    MySQL分表分库

    一样点一下就成《手把手基于Mycat实现MySQL数据拆分》

    SQL优化

    这里列举出来一些用过的,看到的欢迎大家评论区补充讨论

    1、查询尽量避免全表扫描,首先考虑在where、order by字段上添加索引

    2、避免在where字段上使用NULL值,所以在设计表时尽量使用NOT NULL约束,有些数据会默认为NULL,可以设置默认值为0或者-1

    3、避免在where子句中使用!=或<>操作符,Mysql只对<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE使用索引

    4、避免在where中使用OR来连接条件,否则可能导致引擎放弃索引来执行全表扫描,可以使用UNION进行合并查询

          select id from t where num = 30 union select id from t where num = 40;

    5、尽量避免在where子句中进行函数或者表达式操作

    6、最好不要使用select * from t,用具体的字段列表代替"*",不要返回用不到的任何字段

    7、in 和 not in 也要慎用,否则会导致全表扫描,如

    select id from t where num IN(1,2,3)如果是连续的值建议使用between and,select id from t where between 1 and 3;

    8、select id from t where col like %a%;模糊查询左侧有%会导致全表检索,如果需要全文检索可以使用全文搜索引擎比如es,slor

    9、limit offset rows关于分页查询,尽量保证不要出现大的offset,比如limit 10000,10相当于对已查询出来的行数弃掉前10000行后再取10行,完全可以加一些条件过滤一下(完成筛选),而不应该使用limit跳过已查询到的数据。这是一个==offset做无用功==的问题。对应实际工程中,要避免出现大页码的情况,尽量引导用户做条件过滤

    关注本系列文章的朋友应该发现,这里的未完待续已经消失,我们的MySQL优化就告一段落,主要从数据库设计、索引、数据库拆分和SQL语句上进行优化,更多优化方案希望大家通过评论区留言!


     路漫漫其修远兮,吾将上下而求索

    展开全文
  • MySql数据库优化

    千次阅读 2020-01-21 11:36:50
    数据库优化,是一种综合性的技术,不是通过某一种方式让数据库效率提高很多,而是通过各个方面的优化,来是数据库效率明显的稳步的提高。 主要包括以下: 1、库表的设计优化(三种范式) 2、库表添加合适的索引...

    数据库优化,是一种综合性的技术,不是通过某一种方式让数据库效率提高很多,而是通过各个方面的优化,来是数据库效率明显的稳步的提高。

    主要包括以下:

    1、库表的设计优化(三种范式)

    2、库表添加合适的索引(普通索引+主键索引+唯一索引+全文索引)

    3、分表技术-水平分割与垂直分割

    4、读写分离(add/delete/update与select分开)

    5、多用存储过程和触发器(模块化编程)

    6、优化MqSql配置(配置最大并发数,调整缓存大小,my.ini)

    7、SQL优化与慢查询

    8、定时清楚垃圾数据,定时进行碎片整理(MyISAM

    除此之外,还有 MqSql服务器硬件升级

     

    以下进行详细描述

     

    题外话:

    存储引擎:

    MyISAM: 查询速度快,插入速度快,但不支持事务,碎片多;

    InnoDB :5.5版本后Mysql的默认数据库,支持事务,支持ACID事务,支持行级锁定;

    Memory :所有数据置于内存中,拥有极高的插入,适合频繁的数据更新,更新和查询效率。但是会占用和数据量成正比的内存空间。并且其内容会在Mysql重新启动时丢失,不需要保存滴;

    数据库三种模式结构/三级模式 

    外模式(用户):用户所能看到的数据视图,可通过数据库操纵语言对数据进行操作;

    模式(概念):用户视图的最小并集,所有数据的逻辑结构和概念的描述;

    内模式(物理):实际存储组合,内部视图,是实际物理存储的抽象;

     

    一、库表设计

    良好的数据库设计,能够节省数据库空间,保持数据完整性,方便应用程序的开发;(相反:数据冗余,空间浪费,插入更新繁杂或者异常)

    设计数据库

    1、充分了解需求:标识实体(具体存在的对象、东西,名词),标识实体属性,标识实体关系

    以BBS论坛为例

    实体:

    用户(属性:昵称,密码,邮箱,生日,性别,登记,备注,积分,注册时间)

    主贴(属性:标题,正文,发帖时间,状态,发帖人,回复数量,点击数)

    回帖(属性:帖子编号,回帖人,回帖标题,回帖正文,回帖时间,点击数)

    板块(属性:板块名称,版主,板块格言,点击数,发帖数)

     

    2、实体关系

    一对一,两个表的主键是公共字段

    一对多,主键与非主键之间的关系

    多对一,非主键与主键之间 的关系

    多对多,非主键与非主键之间的关系

     

    3、E-R图,实体-联系图(Entity Relationship Diagram),提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型

    *1、创建表时,将实体转化为表,将属性转化为列,唯一标识一行数据的列可为主键,无合适字段做主键就用自动增加列, 将关系转化为主外键展示实体之间的关系;

    *2、表结构规范化-三范式(

    1、列的原子性。列不可分解,确保每列都不能再分解成更基本的数据单位;

    2、记录的唯一标识。给记录增加一个主键,非主键字段依赖主键字段,即表的列中若有重复数据且与主键无关,则可拆分表;

    3、字段不存在冗余。不存在传递依赖,即若表的除主键外各个列间有直接关联,即非主键字段一个字段可以推导出另一个字段,则可拆分表

    范式举例:

    山东理工,山东淄博;山大,山东济南;其中山东济南就可以拆分(第一范式)山东理工,山东,淄博;山大,山东,济南;

    学号-主,姓名;ID,科目,成绩,学号,姓名;满足第二范式;但不满足第三范式;如果学号非主键,则满足第三范式;

     *但注意,也有第五第六等范式,范式越高表越多,查询效率一般就会降低,一般第三范式效率最高列。。

    反三范式:学号,语文,数学,英语,总成绩;总成绩字段就是违反第三范式,适当的数据冗余允许,不然就查询效率低了:select sum(yw+sx+yy) from t_score或单独建表 学号,总成绩;

    由此可见,数据库的性能效率比规范化更重要;

     


    二、库表添加合适的索引

    主键索引,唯一索引见上述链接;

    1、主键索引,主键查询时默认使用;

    2、组合索引,左边用,右边不用;

    3、模糊查询,%或者_写在左边不会用索引,右边会用;

    4、条件语句中如果有or,or的两侧均为索引才能使用,否则不会使用;

    普通索引与组合索引区别:多个普通索引MySQL只用到认为似乎是最有效率的一个单列索引;组合索引为最左前缀,name-age-city建索引,相当于name,age,age-name,city-name;

    主键索引与唯一索引区别:主键执行计划优于唯一,主键索引不能为空,仅一个主键索引列,主键索引更适合自生成不改变的列,主键可被其他列引为外键;

    唯一索引,检索到一个直接返回;普通索引,检查是否是全部才返回;

    创建索引语法:

    create index 索引名称 on 表明 (字段名)

    创建全文索引语法:

    CREATE fulltext INDEX 索引名称 ON 表明 (字段名)

    例子:

    1. SELECT * FROM articles   WHERE MATCH (title,body) AGAINST ('database'); 两个字段的索引:FULLTEXT (title,body)
    2. SELECT * FROM articles WHERE MATCH (tags) AGAINST ('旅游' IN BOOLEAN MODE);IN BOOLEAN MODE是只有含有关键字就行,不用在乎位置,是不是起启位置.

    *仅存储引擎为MyISAM支持全文索引,InnoDB不支持不支持全文索引;

    *mysql默认的阀值是50%,当某字段出现次数只有低于50%(停止词)的才会出现在结果集中;(意思是,全文索引用在海量数据中,不存在高于50%的情况)

    *fulltext不支持中文,用Sphinx是一个基于SQL的全文检索引擎,结合MySQL,PostgreSQL做全文搜索,他可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索;

     

    三、分表

    水平分表:字段不多但是记录行数超级多,达到千万级别,经常检索速度会很慢;按照合理的逻辑去拆分成一个个较小的表,比如按照月份或者类型等待,利于程序简单实现,同时必须考虑到避免union,否则不如不拆分;

    垂直分表:记录不多但是字段较多或者较长,占用的空间也比较大,检索需要大量IO,降低性能;拆分时可将较大字段拆分出来,组成一对一的对应关系表;

     

    四、读写分离

    数据库服务器压力大时,可以利用主从数据库,对仅仅需要查询,且不特别关注失效性的功能,使用从数据库进行数据的查询;

     

    五、存储过程与触发器

    存储过程:可编程的函数,由sql语句和控制结构组成;

    sql:需要先编译后执行;存储过程:跨平台和应用使用;速度快,减少网络流量,组件式编程,统一接口参数安全,灵活性差;

    1

    #语法<br>CREATE PROCEDURE  过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...] 过程体

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    #小示例

    CREATE PROCEDURE proc3(IN parameter int)

      BEGIN

        DECLARE var int;

        SET var=parameter+1;

        IF var=0 THEN

          INSERT INTO VALUES (17);

        END IF ;

        IF parameter=0 THEN

          UPDATE SET s1=s1+1;

        ELSE

          UPDATE SET s1=s1+2;

        END IF ;

      END ;

    存储过程内的普通变量

    1

    2

    #语法:DECLARE 变量名1[,变量名2...] 数据类型 [默认值];

    DECLARE x1 VARCHAR(5) DEFAULT 'outer';  

    变量赋值

    1

    2

    #语法:SET 变量名 = 变量值 [,变量名= 变量值 ...]

    SET x1=x1+1;

    存储过程中的用户变量

    1

    2

    #用户变量一般以@开头

    SET @y='Goodbye Cruel World';

    参与select/update/where语句

    1

    SELECT data1,data2 INTO x1,@y FROM test.table1 LIMIT 1;<br>update test.table1 set data1=@y;<br>insert into test.table1 (data1,data2)values(x1,@y);

    判断语句

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    #IF分支:

    IF 条件1 THEN 语句;

    ELSEIF 条件2 THEN 语句;

    ......

    ELSE 语句;

    END IF;

     

    #CASE分支:

    CASE [条件]

    WHEN 条件1 THEN 语句1

    WHEN 条件2 THEN 语句2 

    ......

    ELSE 语句n

    END CASE

    循环语句

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    LOOP循环:

    LOOP

    语句群

    END LOOP

     

    WHILE语句:

    WHILE 条件 DO

    语句群

    END WHILE

     

    REPEAT UNTIL语句:

    REPEAT

    语句群

    UNTIL 条件

    END REPEAT

    跳转或者终止符

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    ITERATE 语句:  ITERATE只可以出现在LOOP, REPEAT, 和WHILE语句内。ITERATE意思为:“再次循环”   会再次回到label开始位置;

    BEGIN

        DECLARE v INT;

        SET v=0;

        LOOP_LABLE:LOOP

          IF v=3 THEN

            SET v=v+1;

            ITERATE LOOP_LABLE;

          END IF;

          INSERT INTO t VALUES(v);

          SET v=v+1;

          IF v>=5 THEN

            LEAVE LOOP_LABLE;

          END IF;

        END LOOP;

      END;

     

    LEAVE语句:这个语句被用来退出任何被标注的流程控制构造。它和BEGIN ... END或循环一起被使用,像其他语言中的break

    开始结束符

    1

    2

    3

    [begin_label:] BEGIN

    语句群

    END [end_label]

     

     

    七、SQL优化与慢查询

    切入点:一个较大的项目,我们想了解当前mysql的运行状态、是否有耗时较长的sql执行等待

    1、数据库的增删改查

    一般情况下,增删改总计占数据库的10%,而90%是查询操作;

    2、show status的相关常用命令

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    #查看数据库的一些状态

    show status;

    #显示执行了多少条/次的增删改查

    show stauts like 'com_select';

    show stauts like 'com_insert';

    show stauts like 'com_delete';

    show stauts like 'com_update';

    #[session|global] 默认是session会话级-只取出当前窗口的执行;global-从mysql启动到现在

    show global stauts like 'com_select';

     

    #查询当前MySQL本次启动后的运行统计时间(单位:秒)-另外,存储引擎为MyISAM,且运行时间过长,则注意碎片整理

    show status like 'uptime';

    #查看试图连接到MySQL(不管是否连接成功)的连接数

    show status like 'connections';

    #查看线程缓存内的线程的数量。

    show status like 'threads_cached';

     

    #慢查询

    #查看查询时间超过long_query_time秒的查询的个数-即慢查询

    show status like 'slow_queries';

    #可以显示当前慢查询时间(单位:秒)(默认10秒)

    show variables like 'long_query_time';

    #可以修改慢查询时间(单位:秒)

    set long_query_time=1;

      

    3、启动MqSql使用记录慢查询日志(2种)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    #第一种:中括号[]内的部分是可选的,file_name表示日志文件路径

    #在5.5及以上版本的MySQL中,使用如下命令启动:

    mysqld --safe-mode --show-query-log[=1] [--show-query-log-file=file_name]

    #在5.0、5.1等低版本的MySQL中,使用如下命令启动:

    mysqld --log-slow-queries[=file_name]

     

    #第二种:启动命令配置到my.ini中的[mysqld]节点

    [mysqld]

    #设置慢查询界定时间为1秒

    long_query_time=1

    #5.0、5.1等版本配置如下选项

    log-slow-queries="mysql_slow_query.log"

    #5.5及以上版本配置如下选项

    slow-query-log=On

    slow_query_log_file="mysql_slow_query.log"<br><br>

     重启mysql

      停止net stop mysql    启动 net start mysql

     

    4、explain

    explain命令,可以用显示mysql如何使用索引来处理select语句以及连接表; 

    上述图片中的字段再次描述:

    id:查询序号,即执行顺序号,不重要;

    select_type:simple 它表示简单的select,没有union和子查询;primary 最外面的select,在有子查询的语句中,最外面的select查询就是primary;union union语句的第二个或者说是后面那一个;

    table:显示这一行的数据是关于哪张表的;

    possible_keys:可能会使用的索引;

    key:实际使用的索引;优化where语句,选择合适的字段或者表字段;

    key_len:索引长度,越短越好;

    ref:使用某个库表字段 去 匹配表中数据

    rows:查询的行数,越小越好;

    extra:关于mysql如何解析查询的额外信息

      关注当内容显示using temporary,即需要优化sql,因为用到了缓存;--尽力用小表驱动大表

      举例:联表排序:驱动表字段排序直接是驱动表排序/非驱动表排序则先合并结果集后排序(指定联接条件时满足查询条件较少数据表为驱动表,不指定联接条件时表数据较少的为驱动表)

    type:重要,连接类型:

      const 表示:表中最多有一个匹配行,且用到了primary key 或者unique索引;

      eq_ref 表示:和前边表查询匹配的值,后边表中最多仅有一个匹配行,且都用到了primary key 或者unique索引,且是最好的表之间的联接类型

      ref 表示:和前边表匹配的值,后边表均会取出,且基于的关键字段是索引字段,但不是后边表的primary key 或者unique索引,则为ref,且是较好的表之间的联接类型

     

     

     

    八、碎片整理

    存储引擎为MyISAM

    数据insert会使用其占用空间增加,但delete数据不会是其占用的空间减少,原因:删除数据时,mysql并不会回收被已删除数据的占据的存储空间以及索引位;而是等待新的数据来弥补这个空缺;

    语法命令(定期optimize):

    1

    2

    #删除数据后的优化 - 碎片整理

    optimize table 表名

      

    展开全文
  • 全面深入Mysql数据库优化

    千人学习 2019-09-26 11:44:58
    本课程作为MySQL高级课程, 主要讲解了MySQL中的视图/存储过程/触发器/索引等对象的使用、常见的SQL语句优化的技巧 、应用优化、数据库优化、数据库日志等方面的知识,并通过综合案例,对课程中的知识进行一个整合...
  • MySQL数据库优化实践

    千人学习 2019-05-10 08:59:55
    数据库的操作越来越成为整个应用的性能瓶颈了,这点对于Web应用尤其明显。... 课程难点: MySQL引擎优化,和索引优化原理,以及服务器的主从复制,包括sql语法分析等,在web优化中都是我们需要主意的细节。
  • 一、MySQL数据库优化策略

    千次阅读 2020-05-17 18:17:01
    MySQL数据库优化策略 数据库性能取决于数据库级别的几个因素,例如表,查询和配置设置。这些软件结构导致在硬件级别执行CPU和I / O操作,必须将这些操作最小化并使其尽可能高效。在研究数据库性能时,首先要学习软件...
  • Mysql数据库优化方案

    千次阅读 2021-03-30 23:20:21
    1、数据库设计:使用合适的数据类型,使用合适的存储引擎 2、适当创建索引 3、数据库扩展:数据库的分表分库,读写分离等 4、SQL语句优化
  • mysql数据库优化大全

    万次阅读 多人点赞 2018-01-14 00:16:34
    数据库优化 sql语句优化 索引优化 加缓存 读写分离 分区 分布式数据库(垂直切分) 水平切分 MyISAM和InnoDB的区别: 1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动...
  • MySQL数据库优化概述

    千次阅读 2016-06-26 08:57:19
    一,数据库优化的目的 1,避免出现页面访问错误 由于数据库的timeout产生的5**错误; 由于慢查询造成的也没无法加载; 由于阻塞造成数据无法提交;2,增加数据库的稳定性 很多数据库的问题都是由于低效的查询...
  • MySQL数据库优化之索引优化

    千次阅读 2018-07-17 11:52:32
    学习索引优化之前安装演示数据库以供练习 使用mysql提供的sakila数据库 文件下载: http://downloads.mysql.com/docs/sakila-db.tar.gz 解压后导入数据库 shell&gt; mysql -uroot -p &lt; salila-schema....
  • mysql数据库优化总结

    万次阅读 2016-08-15 16:33:33
    一、MySQL的主要适用场景 1、Web网站系统 ...MyISAM存储引擎的表在数据库中,每一个表都被存放为三个以表名命名的物理文件。首先肯定会有任何存储引擎都不可缺少的存放表结构定义信息的.frm文件,另外

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 290,101
精华内容 116,040
关键字:

mysql数据库优化

mysql 订阅