问个mysql优化问题

作者&投稿:艾供 (若有异议请与网页底部的电邮联系)
面试中常问:mysql数据库做哪些优化也提高mysql性能~

在开始演示之前,我们先介绍下两个概念。

概念一,数据的可选择性基数,也就是常说的cardinality值。

查询优化器在生成各种执行计划之前,得先从统计信息中取得相关数据,这样才能估算每步操作所涉及到的记录数,而这个相关数据就是cardinality。简单来说,就是每个值在每个字段中的唯一值分布状态。

比如表t1有100行记录,其中一列为f1。f1中唯一值的个数可以是100个,也可以是1个,当然也可以是1到100之间的任何一个数字。这里唯一值越的多少,就是这个列的可选择基数。

那看到这里我们就明白了,为什么要在基数高的字段上建立索引,而基数低的的字段建立索引反而没有全表扫描来的快。当然这个只是一方面,至于更深入的探讨就不在我这篇探讨的范围了。

概念二,关于HINT的使用。

这里我来说下HINT是什么,在什么时候用。

HINT简单来说就是在某些特定的场景下人工协助MySQL优化器的工作,使她生成最优的执行计划。一般来说,优化器的执行计划都是最优化的,不过在某些特定场景下,执行计划可能不是最优化。

比如:表t1经过大量的频繁更新操作,(UPDATE,DELETE,INSERT),cardinality已经很不准确了,这时候刚好执行了一条SQL,那么有可能这条SQL的执行计划就不是最优的。为什么说有可能呢?

来看下具体演示

譬如,以下两条SQL,
A:
select * from t1 where f1 = 20;B:
select * from t1 where f1 = 30;如果f1的值刚好频繁更新的值为30,并且没有达到MySQL自动更新cardinality值的临界值或者说用户设置了手动更新又或者用户减少了sample page等等,那么对这两条语句来说,可能不准确的就是B了。
这里顺带说下,MySQL提供了自动更新和手动更新表cardinality值的方法,因篇幅有限,需要的可以查阅手册。
那回到正题上,MySQL 8.0 带来了几个HINT,我今天就举个index_merge的例子。
示例表结构:
mysql> desc t1;+------------+--------------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+------------+--------------+------+-----+---------+----------------+| id | int(11) | NO | PRI | NULL | auto_increment || rank1 | int(11) | YES | MUL | NULL | || rank2 | int(11) | YES | MUL | NULL | || log_time | datetime | YES | MUL | NULL | || prefix_uid | varchar(100) | YES | | NULL | || desc1 | text | YES | | NULL | || rank3 | int(11) | YES | MUL | NULL | |+------------+--------------+------+-----+---------+----------------+7 rows in set (0.00 sec)表记录数:
mysql> select count(*) from t1;+----------+| count(*) |+----------+| 32768 |+----------+1 row in set (0.01 sec)这里我们两条经典的SQL:
SQL C:
select * from t1 where rank1 = 1 or rank2 = 2 or rank3 = 2;SQL D:
select * from t1 where rank1 =100 and rank2 =100 and rank3 =100;表t1实际上在rank1,rank2,rank3三列上分别有一个二级索引。
那我们来看SQL C的查询计划。
显然,没有用到任何索引,扫描的行数为32034,cost为3243.65。
mysql> explain format=json select * from t1 where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "3243.65" }, "table": { "table_name": "t1", "access_type": "ALL", "possible_keys": [ "idx_rank1", "idx_rank2", "idx_rank3" ], "rows_examined_per_scan": 32034, "rows_produced_per_join": 115, "filtered": "0.36", "cost_info": { "read_cost": "3232.07", "eval_cost": "11.58", "prefix_cost": "3243.65", "data_read_per_join": "49K" }, "used_columns": [ "id", "rank1", "rank2", "log_time", "prefix_uid", "desc1", "rank3" ], "attached_condition": "((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))" } }}1 row in set, 1 warning (0.00 sec)我们加上hint给相同的查询,再次看看查询计划。
这个时候用到了index_merge,union了三个列。扫描的行数为1103,cost为441.09,明显比之前的快了好几倍。
mysql> explain format=json select /*+ index_merge(t1) */ * from t1 where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "441.09" }, "table": { "table_name": "t1", "access_type": "index_merge", "possible_keys": [ "idx_rank1", "idx_rank2", "idx_rank3" ], "key": "union(idx_rank1,idx_rank2,idx_rank3)", "key_length": "5,5,5", "rows_examined_per_scan": 1103, "rows_produced_per_join": 1103, "filtered": "100.00", "cost_info": { "read_cost": "330.79", "eval_cost": "110.30", "prefix_cost": "441.09", "data_read_per_join": "473K" }, "used_columns": [ "id", "rank1", "rank2", "log_time", "prefix_uid", "desc1", "rank3" ], "attached_condition": "((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))" } }}1 row in set, 1 warning (0.00 sec)我们再看下SQL D的计划:
不加HINT,
mysql> explain format=json select * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "534.34" }, "table": { "table_name": "t1", "access_type": "ref", "possible_keys": [ "idx_rank1", "idx_rank2", "idx_rank3" ], "key": "idx_rank1", "used_key_parts": [ "rank1" ], "key_length": "5", "ref": [ "const" ], "rows_examined_per_scan": 555, "rows_produced_per_join": 0, "filtered": "0.07", "cost_info": { "read_cost": "478.84", "eval_cost": "0.04", "prefix_cost": "534.34", "data_read_per_join": "176" }, "used_columns": [ "id", "rank1", "rank2", "log_time", "prefix_uid", "desc1", "rank3" ], "attached_condition": "((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100))" } }}1 row in set, 1 warning (0.00 sec)加了HINT,
mysql> explain format=json select /*+ index_merge(t1)*/ * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: { "query_block": { "select_id": 1, "cost_info": { "query_cost": "5.23" }, "table": { "table_name": "t1", "access_type": "index_merge", "possible_keys": [ "idx_rank1", "idx_rank2", "idx_rank3" ], "key": "intersect(idx_rank1,idx_rank2,idx_rank3)", "key_length": "5,5,5", "rows_examined_per_scan": 1, "rows_produced_per_join": 1, "filtered": "100.00", "cost_info": { "read_cost": "5.13", "eval_cost": "0.10", "prefix_cost": "5.23", "data_read_per_join": "440" }, "used_columns": [ "id", "rank1", "rank2", "log_time", "prefix_uid", "desc1", "rank3" ], "attached_condition": "((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100) and (`ytt`.`t1`.`rank1` = 100))" } }}1 row in set, 1 warning (0.00 sec)对比下以上两个,加了HINT的比不加HINT的cost小了100倍。
总结下,就是说表的cardinality值影响这张的查询计划,如果这个值没有正常更新的话,就需要手工加HINT了。相信MySQL未来的版本会带来更多的HINT。

数量少的时候,差别微乎其微,

数据量大的时候,扫描的表的行数受条件限制,都一样,问题出在你用*,扫描返回的数据量要大于列出具体字段。可以理解为I/O支出相对要多,慢就是慢在I/O的支出上而已。

至于不推荐select *的原因更多在于能比较好的纠错,毕竟select出来具体字段,查错远比所有字段快一点。

在开始演示之前,我们先介绍下两个概念。


概念一,数据的可选择性基数,也就是常说的cardinality值。


查询优化器在生成各种执行计划之前,得先从统计信息中取得相关数据,这样才能估算每步操作所涉及到的记录数,而这个相关数据就是cardinality。简单来说,就是每个值在每个字段中的唯一值分布状态。


比如表t1有100行记录,其中一列为f1。f1中唯一值的个数可以是100个,也可以是1个,当然也可以是1到100之间的任何一个数字。这里唯一值越的多少,就是这个列的可选择基数。


那看到这里我们就明白了,为什么要在基数高的字段上建立索引,而基数低的的字段建立索引反而没有全表扫描来的快。当然这个只是一方面,至于更深入的探讨就不在我这篇探讨的范围了。


概念二,关于HINT的使用。


这里我来说下HINT是什么,在什么时候用。


HINT简单来说就是在某些特定的场景下人工协助MySQL优化器的工作,使她生成最优的执行计划。一般来说,优化器的执行计划都是最优化的,不过在某些特定场景下,执行计划可能不是最优化。


比如:表t1经过大量的频繁更新操作,(UPDATE,DELETE,INSERT),cardinality已经很不准确了,这时候刚好执行了一条SQL,那么有可能这条SQL的执行计划就不是最优的。为什么说有可能呢?


来看下具体演示


譬如,以下两条SQL,

  • A:

  • select * from t1 where f1 = 20;

  • B:

  • select * from t1 where f1 = 30;

  • 如果f1的值刚好频繁更新的值为30,并且没有达到MySQL自动更新cardinality值的临界值或者说用户设置了手动更新又或者用户减少了sample page等等,那么对这两条语句来说,可能不准确的就是B了。

    这里顺带说下,MySQL提供了自动更新和手动更新表cardinality值的方法,因篇幅有限,需要的可以查阅手册。

    那回到正题上,MySQL 8.0 带来了几个HINT,我今天就举个index_merge的例子。

    示例表结构:

  • mysql> desc t1;+------------+--------------+------+-----+---------+----------------+| Field      | Type         | Null | Key | Default | Extra          |+------------+--------------+------+-----+---------+----------------+| id         | int(11)      | NO   | PRI | NULL    | auto_increment || rank1      | int(11)      | YES  | MUL | NULL    |                || rank2      | int(11)      | YES  | MUL | NULL    |                || log_time   | datetime     | YES  | MUL | NULL    |                || prefix_uid | varchar(100) | YES  |     | NULL    |                || desc1      | text         | YES  |     | NULL    |                || rank3      | int(11)      | YES  | MUL | NULL    |                |+------------+--------------+------+-----+---------+----------------+7 rows in set (0.00 sec)

  • 表记录数:

  • mysql> select count(*) from t1;+----------+| count(*) |+----------+|    32768 |+----------+1 row in set (0.01 sec)

  • 这里我们两条经典的SQL:

  • SQL C:

  • select * from t1 where rank1 = 1 or rank2 = 2 or rank3 = 2;

  • SQL D:

  • select * from t1 where rank1 =100  and rank2 =100  and rank3 =100;

  • 表t1实际上在rank1,rank2,rank3三列上分别有一个二级索引。

    那我们来看SQL C的查询计划。

    显然,没有用到任何索引,扫描的行数为32034,cost为3243.65。

  • mysql> explain  format=json select * from t1  where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: {  "query_block": {    "select_id": 1,    "cost_info": {      "query_cost": "3243.65"    },    "table": {      "table_name": "t1",      "access_type": "ALL",      "possible_keys": [        "idx_rank1",        "idx_rank2",        "idx_rank3"      ],      "rows_examined_per_scan": 32034,      "rows_produced_per_join": 115,      "filtered": "0.36",      "cost_info": {        "read_cost": "3232.07",        "eval_cost": "11.58",        "prefix_cost": "3243.65",        "data_read_per_join": "49K"      },      "used_columns": [        "id",        "rank1",        "rank2",        "log_time",        "prefix_uid",        "desc1",        "rank3"      ],      "attached_condition": "((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))"    }  }}1 row in set, 1 warning (0.00 sec)

  • 我们加上hint给相同的查询,再次看看查询计划。

    这个时候用到了index_merge,union了三个列。扫描的行数为1103,cost为441.09,明显比之前的快了好几倍。

  • mysql> explain  format=json select /*+ index_merge(t1) */ * from t1  where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: {  "query_block": {    "select_id": 1,    "cost_info": {      "query_cost": "441.09"    },    "table": {      "table_name": "t1",      "access_type": "index_merge",      "possible_keys": [        "idx_rank1",        "idx_rank2",        "idx_rank3"      ],      "key": "union(idx_rank1,idx_rank2,idx_rank3)",      "key_length": "5,5,5",      "rows_examined_per_scan": 1103,      "rows_produced_per_join": 1103,      "filtered": "100.00",      "cost_info": {        "read_cost": "330.79",        "eval_cost": "110.30",        "prefix_cost": "441.09",        "data_read_per_join": "473K"      },      "used_columns": [        "id",        "rank1",        "rank2",        "log_time",        "prefix_uid",        "desc1",        "rank3"      ],      "attached_condition": "((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))"    }  }}1 row in set, 1 warning (0.00 sec)

  • 我们再看下SQL D的计划:

  • 不加HINT,

  • mysql> explain format=json select * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: {  "query_block": {    "select_id": 1,    "cost_info": {      "query_cost": "534.34"    },    "table": {      "table_name": "t1",      "access_type": "ref",      "possible_keys": [        "idx_rank1",        "idx_rank2",        "idx_rank3"      ],      "key": "idx_rank1",      "used_key_parts": [        "rank1"      ],      "key_length": "5",      "ref": [        "const"      ],      "rows_examined_per_scan": 555,      "rows_produced_per_join": 0,      "filtered": "0.07",      "cost_info": {        "read_cost": "478.84",        "eval_cost": "0.04",        "prefix_cost": "534.34",        "data_read_per_join": "176"      },      "used_columns": [        "id",        "rank1",        "rank2",        "log_time",        "prefix_uid",        "desc1",        "rank3"      ],      "attached_condition": "((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100))"    }  }}1 row in set, 1 warning (0.00 sec)

  • 加了HINT,

  • mysql> explain format=json select /*+ index_merge(t1)*/ * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: {  "query_block": {    "select_id": 1,    "cost_info": {      "query_cost": "5.23"    },    "table": {      "table_name": "t1",      "access_type": "index_merge",      "possible_keys": [        "idx_rank1",        "idx_rank2",        "idx_rank3"      ],      "key": "intersect(idx_rank1,idx_rank2,idx_rank3)",      "key_length": "5,5,5",      "rows_examined_per_scan": 1,      "rows_produced_per_join": 1,      "filtered": "100.00",      "cost_info": {        "read_cost": "5.13",        "eval_cost": "0.10",        "prefix_cost": "5.23",        "data_read_per_join": "440"      },      "used_columns": [        "id",        "rank1",        "rank2",        "log_time",        "prefix_uid",        "desc1",        "rank3"      ],      "attached_condition": "((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100) and (`ytt`.`t1`.`rank1` = 100))"    }  }}1 row in set, 1 warning (0.00 sec)

  • 对比下以上两个,加了HINT的比不加HINT的cost小了100倍。

    总结下,就是说表的cardinality值影响这张的查询计划,如果这个值没有正常更新的话,就需要手工加HINT了。相信MySQL未来的版本会带来更多的HINT。



在一张有几百万个大数据的表中,MySQL的处理引擎会查找得很慢,这时,就必须采用分表甚至分库的方法。


你可以参考这篇文章:《MySQL大数据处理》

http://www.cnblogs.com/buffer/archive/2011/04/16/2018531.html

摘录如下:

一、概述


分表是个目前算是比较炒的比较流行的概念,特别是在大负载的情况下,分表是一个良好分散数据库压力的好方法。


首先要了解为什么要分表,分表的好处是什么。我们先来大概了解以下一个数据库执行SQL的过程:


接收到SQL --> 放入SQL执行队列 --> 使用分析器分解SQL --> 按照分析结果进行数据的提取或者修改 --> 返回处理结果


当然,这个流程图不一定正确,这只是我自己主观意识上这么我认为。那么这个处理过程当中,最容易出现问题的是什么?就是说,如果前一个SQL没
有执行完毕的话,后面的SQL是不会执行的,因为为了保证数据的完整性,必须对数据表文件进行锁定,包括共享锁和独享锁两种锁定。共享锁是在锁定的期间,
其它线程也可以访问这个数据文件,但是不允许修改操作,相应的,独享锁就是整个文件就是归一个线程所有,其它线程无法访问这个数据文件。一般MySQL中
最快的存储引擎MyISAM,它是基于表锁定的,就是说如果一锁定的话,那么整个数据文件外部都无法访问,必须等前一个操作完成后,才能接收下一个操作,
那么在这个前一个操作没有执行完成,后一个操作等待在队列里无法执行的情况叫做阻塞,一般我们通俗意义上叫做“锁表”。


锁表直接导致的后果是什么?就是大量的SQL无法立即执行,必须等队列前面的SQL全部执行完毕才能继续执行。这个无法执行的SQL就会导致没有结果,或者延迟严重,影响用户体验。


特别是对于一些使用比较频繁的表,比如SNS系统中的用户信息表、论坛系统中的帖子表等等,都是访问量大很大的表,为了保证数据的快速提取返回给用户,必须使用一些处理方式来解决这个问题,这个就是我今天要聊到的分表技术。


分表技术顾名思义,就是把若干个存储相同类型数据的表分成几个表分表存储,在提取数据的时候,不同的用户访问不同的表,互不冲突,减少锁表的几
率。比如,目前保存用户分表有两个表,一个是user_1表,还有一个是 user_2 表,两个表保存了不同的用户信息,user_1
保存了前10万的用户信息,user_2保存了后10万名用户的信息,现在如果同时查询用户 heiyeluren1 和 heiyeluren2
这个两个用户,那么就是分表从不同的表提取出来,减少锁表的可能。


我下面要讲述的两种分表方法我自己都没有实验过,不保证准确能用,只是提供一个设计思路。下面关于分表的例子我假设是在一个贴吧系统的基础上来进行处理和构建的。(如果没有用过贴吧的用户赶紧Google一下)


二、基于基础表的分表处理


这个基于基础表的分表处理方式大致的思想就是:一个主要表,保存了所有的基本信息,如果某个项目需要找到它所存储的表,那么必须从这个基础表中
查找出对应的表名等项目,好直接访问这个表。如果觉得这个基础表速度不够快,可以完全把整个基础表保存在缓存或者内存中,方便有效的查询。


我们基于贴吧的情况,构建假设如下的3张表:


1. 贴吧版块表: 保存贴吧中版块的信息


2. 贴吧主题表:保存贴吧中版块中的主题信息,用于浏览


3. 贴吧回复表:保存主题的原始内容和回复内容


“贴吧版块表”包含如下字段:


版块ID       board_id          int(10)


版块名称    board_name      char(50)


子表ID       table_id            smallint(5)


产生时间    created             datetime


“贴吧主题表”包含如下字段:


主题ID          topic_id        int(10)


主题名称        topic_name     char(255)


版块ID          board_id          int(10)


创建时间       created           datetime


“贴吧回复表”的字段如下:


回复ID        reply_id           int(10)


回复内容      reply_text        text


主题ID        topic_id           int(10)


版块ID        board_id         int(10)


创建时间      created            datetime


那么上面保存了我们整个贴吧中的表结构信息,三个表对应的关系是:


版块 --> 多个主题


主题 --> 多个回复


那么就是说,表文件大小的关系是:


版块表文件 < 主题表文件 < 回复表文件


所以基本可以确定需要对主题表和回复表进行分表,已增加我们数据检索查询更改时候的速度和性能。


看了上面的表结构,会明显发现,在“版块表”中保存了一个"table_id"字段,这个字段就是用于保存一个版块对应的主题和回复都是分表保存在什么表里的。


比如我们有一个叫做“PHP”的贴吧,board_id是1,子表ID也是1,那么这条记录就是:


board_id | board_name | table_id | created


1 | PHP | 1 | 2007-01-19 00:30:12


相应的,如果我需要提取“PHP”吧里的所有主题,那么就必须按照表里保存的table_id来组合一个存储了主题的表名称,比如我们主题表的前缀是“topic_”,那么组合出来“PHP”吧对应的主题表应该是:“topic_1”,那么我们执行:


SELECT * FROM topic_1 WHERE board_id = 1 ORDER BY topic_id DESC LIMIT 10


这样就能够获取这个主题下面回复列表,方便我们进行查看,如果需要查看某个主题下面的回复,我们可以继续使用版块表中保存的“table_id”来进行查询。比如我们回复表的前缀是“reply_”,那么就可以组合出“PHP”吧的ID为1的主题的回复:


SELECT * FROM reply_1 WHERE topic_id = 1 ORDER BY reply_id DESC LIMIT 10


这里,我们能够清晰的看到,其实我们这里使用了基础表,基础表就是我们的版块表。那么相应的,肯定会说:基础表的数据量大了以后如何保证它的速度和效率?


当然,我们就必须使得这个基础表保持最好的速度和性能,比如,可以采用MySQL的内存表来存储,或者保存在内存当中,比如Memcache之类的内存缓存等等,可以按照实际情况来进行调整。


一般基于基础表的分表机制在SNS、交友、论坛等Web2.0网站中是个比较不错的解决方案,在这些网站中,完全可以单独使用一个表来来保存基本标识和目标表之间的关系。使用表保存对应关系的好处是以后扩展非常方便,只需要增加一个表记录。


【优势】增加删除节点非常方便,为后期升级维护带来很大便利


【劣势】需要增加表或者对某一个表进行操作,还是无法离开数据库,会产生瓶颈


三、基于Hash算法的分表处理


我们知道Hash表就是通过某个特殊的Hash算法计算出的一个值,这个值必须是惟一的,并且能够使用这个计算出来的值查找到需要的值,这个叫做哈希表。


我们在分表里的hash算法跟这个思想类似:通过一个原始目标的ID或者名称通过一定的hash算法计算出数据存储表的表名,然后访问相应的表。


继续拿上面的贴吧来说,每个贴吧有版块名称和版块ID,那么这两项值是固定的,并且是惟一的,那么我们就可以考虑通过对这两项值中的一项进行一些运算得出一个目标表的名称。


现在假如我们针对我们这个贴吧系统,假设系统最大允许1亿条数据,考虑每个表保存100万条记录,那么整个系统就不超过100个表就能够容纳。按照这个标准,我们假设在贴吧的版块ID上进行hash,获得一个key值,这个值就是我们的表名,然后访问相应的表。


我们构造一个简单的hash算法:


function get_hash($id){
     $str = bin2hex($id);
     $hash = substr($str, 0, 4);
     if (strlen($hash)<4){
         $hash = str_pad($hash, 4, "0");
     }
     return $hash;
}


算法大致就是传入一个版块ID值,然后函数返回一个4位的字符串,如果字符串长度不够,使用0进行补全。


比如:get_hash(1),输出的结果是“3100”,输入:get_hash(23819),得到的结果是:3233,那么我们经过简单的跟表前缀组合,就能够访问这个表了。那么我们需要访问ID为1的内容时候哦,组合的表将是:topic_3100、reply_3100,那么就可以直接对目标表进行访问了。


当然,使用hash算法后,有部分数据是可能在同一个表的,这一点跟hash表不同,hash表是尽量解决冲突,我们这里不需要,当然同样需要预测和分析表数据可能保存的表名。


如果需要存储的数据更多,同样的,可以对版块的名字进行hash操作,比如也是上面的二进制转换成十六进制,因为汉字比数字和字母要多很多,那么重复几率更小,但是可能组合成的表就更多了,相应就必须考虑一些其它的问题。


归根结底,使用hash方式的话必须选择一个好的hash算法,才能生成更多的表,然数据查询的更迅速。


【优点hash算法直接得出目标表名称,效率很高】通过


【劣势】扩展性比较差,选择了一个hash算法,定义了多少数据量,以后只能在这个数据量上跑,不能超过过这个数据量,可扩展性稍差


四、其它问题


1. 搜索问题


现在我们已经进行分表了,那么就无法直接对表进行搜索,因为你无法对可能系统中已经存在的几十或者几百个表进行检索,所以搜索必须借助第三方的组件来进行,比如Lucene作为站内搜索引擎是个不错的选择。


2. 表文件问题


我们知道MySQL的MyISAM引擎每个表都会生成三个文件,*.frm、*.MYD、*.MYI
三个文件,分表用来保存表结构、表数据和表索引。Linux下面每个目录下的文件数量最好不要超过1000个,不然检索数据将更慢,那么每个表都会生成三
个文件,相应的如果分表超过300个表,那么将检索非常慢,所以这时候就必须再进行分,比如在进行数据库的分离。


使用基础表,我们可以新增加一个字段,用来保存这个表保存在什么数据。使用Hash的方式,我们必须截取hash值中第几位来作为数据库的名字。这样,完好的解决这个问题。


五、总结


在大负载应用当中,数据库一直是个很重要的瓶颈,必须要突破,本文讲解了两种分表的方式,希望对很多人能够有启发的作用。当然,本文代码和设想没有经过任何代码测试,所以无法保证设计的完全准确实用,具体还是需要读者在使用过程当中认真分析实施。



  数据库优化的问题需要从多个角度考虑:

  一、针对数据库结构和查询的优化:
  在一般的应用中,合理的数据表结构和索引的设计,能够最大化查询性能。即时在千万级别的数据表中,针对主键的查询也会非常快速。在数据量太大的情况下,没有使用索引的查询可能会非常缓慢。where条件会用到的字段中,要尽量都加上索引。模糊查询可以通过全文索引来优化。另外,单条记录的长短也会对查询速率产生一定的影响(记录越长,磁盘读取数据时需要移动的距离就越长)。一些关键的数据最好放在小表中。存储引擎的选择也很重要。MYISAM引擎的查询性能最好,而且支持全文索引。MYISAM的索引是压缩存储的,可以节约磁盘空间。更重要的时,它可以将更多的索引加载到内存中,大大提高查询效率。

  二、针对架构的优化:
  在高并发的应用中,仅仅针对数据库层面的优化已经力不从心。数据库的能力是有限的,最优秀的数据库也存在性能瓶颈。大量的并发查询将导致数据库不堪重负。主从库、读写分离是常见的优化方式。对于一些经常访问的热数据,每次都执行数据库查询会造成资源浪费,而且非常低效。如果将这些热的数据以key-value(键和值)的方式存储在内存中,可以最大化性能。

  一些热门的应用,如你提到的微博,除了做好数据库方面的优化外,架构优化非常关键。本例中,可以为每个用户单独存储好友的最新微博。在用户发布微博时,将这条微博的ID存储在所有好友的“最新微博”中。数据满30条时,同时删除旧的数据。这样在获取好友最新微博时,不需要查询数据库,效率非常高。

大型项目,一般采用子表,即当用户注册后,为此用户建立单独的数据表。


实战!聊聊如何解决MySQL深分页问题
前言大家好,我是捡田螺的小男孩。我们日常做分页需求时,一般会用limit实现,但是当偏移量特别大的时候,查询效率就变得低下。本文将分4个方案,讨论如何优化MySQL百万数据的深分页问题,并附上最近优化生产慢SQL的实战案例。limit深分页为什么会变慢?先看下表结构哈:CREATETABLEaccount(idint(11)NOT...

面试题168道MySQL面试题拿下DreamJob的机会在此168道mysql
root -p password database_name > a.sql 总结:本文提供了一些有关MySQL的面试问题,帮助你更好的准备自己,并最终拿下Dream Job。尽管这些问题可能不会在每个面试中都被问到,但它们提供了一种全面了解MySQL功能的途径,并且花费时间和精力来学习和了解MySQL运作机制和优化技术,无疑是非常有益的。

如何更好的优化MySQL数据库
使用EXPLAIN关键字是另一个MySQL优化技巧,可以让你了解MySQL正在进行什么样的查询操作这可以帮助你发现瓶颈的所在,并显示出查询或表结构在哪里出了问题。EXPLAIN查询的结果,可以告诉你那些索引正在被引用,表是如何被扫描和排序的等等。实现一个SELECT查询(最好是比较复杂的一个,带joins方式的),在里面添加上你的关键词...

MySQL下的三重连接查询优化mysql三重连接查询
三重连接查询是指在多个表中进行联合查询,其中每个表之间都要进行两次连接操作。比如,有三个表A、B、C,其中A与B连接一次,B与C连接一次,最终结果呈现A、B、C三个表的关联信息。这种查询过程中,MySQL需要进行多次查询,因此时间复杂度较高,查询效率也较低。二、如何进行三重连接查询的优化?1....

mysql分页优化问题,主键ID并非自增的整形
添加 添加约束: alter table table-name add index index-name (column[dataName])自动自增 1,2, 3.。。。

MySQL中AND运算符的优化措施mysql中and的优化
3. 优化数据结构:通过优化MySQL系统的数据结构,可以提升系统的性能和效率。示例代码:ALTER TABLE table ADD INDEX (condition1, condition2, condition3);三、测试结果 为了测试优化效果,我们针对一个包含100万条数据的表进行测试,分别使用优化前和优化后的SELECT语句进行查询,并记录查询所需时间。1....

MySQL中limit等查询优化技巧mysql中limit等
以上查询语句将返回从第20条数据开始,取10条数据。如果要优化查询速度,可以使用类似以下的方式:SELECT * FROM table_name WHERE id > 上一页的最后一个id LIMIT 10;在上述查询语句中,WHERE子句根据上一页查询结果中最后一个id值,提高了查询效率。3. 避免使用函数 函数是MySQL中常用的数据处理方式...

mysql调优的几种方式
MySQL调优是许多网站和公司的重要任务之一。MySQL是一个非常流行的关系型数据库管理系统,因此对其进行优化可以提高网站的性能和响应时间。下面介绍一些MySQL调优的常用方法:1. 使用索引:索引是MySQL中一种优化查询速度的技术。在处理大量数据时,索引可以显著提高查询速度。要使用索引,需要在数据库表中添加...

从编译到工具:几种Mysql的优化方法
一、在编译时优化mysql如果你从源代码分发安装mysql,要注意,编译过程对以后的目标程序性能有重要的影响,不同的编译方式可能得到类似的目标文件,但性能可能相差很大,因此,在编译安装mysql适应仔细根据你的应用类型选择最可能好的编译选项。这种定制的mysql可以为你的应用提供最佳性能。技巧:选用较好的编译...

如何优化 MySQL 索引:提高排序性能
这篇文章继续讨论优化 MySQL 索引。如果您还没有阅读过上一篇有关 MySQL 索引优化的文章(第 1 部分),我建议您在继续阅读本文之前先阅读一下。这篇博文的主要重点是讨论MySQL的Order By 功能背后的原理。注意:下面提到的所有测试均在MySQL 5.7. 使用MySQL 8时结果可能会有所不同。order by语句也...

东港市18031385362: Mysql数据库优化可以从哪几个方面优化 -
赤军儿感: 1、选取最适用的字段属性 MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小. 2、使...

东港市18031385362: mysql优化应该怎么做? -
赤军儿感: 在传智播客的官网视频中有专门的讲解mysql优化,浅显易懂你可以去找一下.总结就是一下几个方面:(1)服务器性能优化 (2)数据库引擎优化,索引优化 (3)数据库读写分离,分库分表

东港市18031385362: mysql 优化包括哪些内容? -
赤军儿感: mysql的优化大的有两方面:1、配置优化配置的优化其实包含两个方面的:操作系统内核的优化和mysql配置文件的优化1)系统内核的优化对专用的mysql服务器来说,无非是内存实用、连接数、超时处理、TCP处理等方面的优化,根据自己...

东港市18031385362: 如何优化mysql数据库 -
赤军儿感: 1 适当建立索引2 对表进行水平划分3 选择适当的字段类型,特别是主键4 文件、图片等大文件用文件系统存储,不用数据库5 外键表示清楚,方便建立索引6 宁可集中批量操作,避免频繁读写7 选择合适的引擎8 sql语句优化

东港市18031385362: mysql数据库怎么优化,有几方面的优化? -
赤军儿感: 我列举几个我熟悉的,1,存储引擎,根据应用选择合适的引擎2,索引 ----这个就有很多文章了,具体需要你自己去了解3,sql语句优化,查询条件的选择之类4,mysql自身系统配置,需要针对应用去定制5,表的选择,临时表,或者分区表,也需要针对应用的情况去选择使用

东港市18031385362: 面试中常问:mysql数据库做哪些优化也提高mysql性能 -
赤军儿感: Mysql占用CPU过高的时候,该从哪些方面下手进行优化? 占用CPU过高,可以做如下考虑: 1)一般来讲,排除高并发的因素,还是要找到导致你CPU过高的哪几条在执行的SQL,show processlist语句,查找负荷最重的SQL语句,优化该SQL...

东港市18031385362: MySQL数据库基本的三个优化法则是什么? -
赤军儿感: (1)系统服务优化,把MySQL的key_buffer、cache_buffer、query_cache等增加容量 (2)给所有经常查询的字段增加适当的索引 (3)优化SQL语句,减少Ditinct、Group、Join等等语句的操作

东港市18031385362: 优化MYSQL数据库的方法 -
赤军儿感: 1、选取最适用的字段属性,尽可能减少定义字段长度,尽量把字段设置NOT NULL,例如'省份,性别',最好设置为ENUM2、使用连接(JOIN)来代替子查询: a.删除没有任何订单客户:DELETE FROM customerinfo WHERE customerid NOT ...

东港市18031385362: MySQL服务器如何进行调优?? -
赤军儿感: 第一种方法时替换有问题的硬件.对MySQL进程的设置进行调优.对查询e799bee5baa6e78988e69d8331333337626263进行优化.替换有问题的硬件通常是我们的第一考虑,主要原因是数据库会占用大量资源.不过这种解决方案也就仅限于...

东港市18031385362: 面试被问到怎么优化mysql? -
赤军儿感: 根据服务器配置mysql性能优化参数,从系统层面增强mysql的性能 优化数据表结构,字段类型,字段索引,分表,分库,读写分离等等,从数据库层面增强性能

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网