SQL statement optimization approach - Advanced articles

MYSQL performance

The maximum amount of data

Despite the amount of data and the number of concurrent, talk about performance are crap (pull the most painful kind) .Mysql no limit to the number of single-table maximum records, it depends on the operating system limit on file size

File system Single file size limit
FAT32 (32-bit binary number records management disk files) The largest 4G
NTFS (WindowsNT environment file system)   The maximum 64G
NTFS5.0 (NTFS5.0 is a recoverable file system) The maximum 2TB
EXT2 (second generation extended file system) Block size is 1024 bytes, the maximum capacity of 16GB file; a block size of 4096 bytes, the maximum capacity of the file 2TB
EXT3 (third generation extended file system) Block size is 4kb, the maximum capacity of the file 4TB
EXT4 (fourth-generation extended file system) Theory can be greater than 16TB

 

"Ali Baba Java Development Manual" put forward a single table rows over 5 million lines or single-table capacity of more than 2GB, it is recommended sub-library sub-table. Performance is determined by a combination of factors, put aside the complexity of the business, the impact is followed by the hardware configuration, MySQL configuration, data table design, index optimization. 5000000 This value is only for reference, not an iron law.

The maximum number of concurrent

  The number of concurrent database can refer to the same time the number of requests processed, is determined by the max_connections and max_user_connections. refers to the maximum number of connections max_connections MySQL instance, the upper limit value is 16384, max_user_connections is the maximum number of database connections per user.

  MySQL will provide a buffer for each connection, which means consuming more memory. If the connections are set too high hardware too much, is too low and can not take full advantage of the hardware. General requirements for both the ratio exceeds 10%, calculated as follows:

max_used_connections / max_connections * 100% = 3/100 *100% ≈ 3%

  查看最大连接数与响应最大连接数:

show variables like '%max_connections%';
show variables like '%max_user_connections%';

  在配置文件my.cnf中修改最大连接数

[mysqld]
max_connections = 100
max_used_connections = 20

  查询耗时0.5秒

  建议将单次查询耗时控制在0.5秒以内,0.5秒是个经验值,源于用户体验的3秒原则。如果用户的操作3秒内没有响应,将会厌烦甚至退出。响应时间=客户端UI渲染耗时+网络请求耗时+应用程序处理耗时+查询数据库耗时,0.5秒就是留给数据库1/6的处理时间。

  实施原则

  mysql特点扩容难,容量小并发低,SQL约束太多,应用程序扩容比数据库要容易多,实施原则数据库少干活,应用程序多干活.

    •   充分利用但不滥用索引,须知索引也消耗磁盘和CPU。
    •   不推荐使用数据库函数格式化数据,交给应用程序处理。
    •   不推荐使用外键约束,用应用程序保证数据准确性。
    •   写多读少的场景,不推荐使用唯一索引,用应用程序保证唯一性。
    •   适当冗余字段,尝试创建中间表,用应用程序计算中间结果,用空间换时间。
    •   不允许执行极度耗时的事务,配合应用程序拆分成更小的事务。
    •   预估重要数据表(比如订单表)的负载和数据增长态势,提前优化。

数据库表设计

  数据类型

   数据类型的选择原则:更简单或者占用空间更小。

 

    • 如果长度能够满足,整型尽量使用tinyint、smallint、medium_int而非int。
    • 如果字符串长度确定,采用char类型。
    • 如果varchar能够满足,不采用text类型。
    • 精度要求较高的使用decimal类型,也可以使用BIGINT,比如精确两位小数就乘以100后保存。
    • 尽量采用timestamp而非datetime。 

  避免空值

    MySQL中字段为NULL时依然占用空间,会使索引、索引统计更加复杂。从NULL值更新到非NULL无法做到原地更新,容易发生索引分裂影响性能。尽可能将NULL值用有意义的值代替,也能避免SQL语句里面包含is not null的判断。

  

  text类型优化

  由于text字段储存大量数据,表容量会很早涨上去,影响其他字段的查询性能。建议抽取出来放在子表里,用业务主键关联。

 

  索引优化-索引分类

  • 普通索引:最基本的索引。
  • 组合索引:多个字段上建立的索引,能够加速复合查询条件的检索。
  • 唯一索引:与普通索引类似,但索引列的值必须唯一,允许有空值。
  • 组合唯一索引:列值的组合必须唯一。
  • 主键索引:特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用primary key约束。
  • 全文索引:用于海量文本的查询,MySQL5.6之后的InnoDB和MyISAM均支持全文索引。由于查询精度以及扩展性不佳,更多的企业选择Elasticsearch。

  索引优化

  • 分页查询很重要,如果查询数据量超过30%,MYSQL不会使用索引。
  • 单表索引数不超过5个、单个索引字段数不超过5个。
  • 字符串可使用前缀索引,前缀长度控制在5-8个字符。
  • 字段唯一性太低,增加索引没有意义,如:是否删除、性别。
  • 合理使用覆盖索引,如下所示:

select login_name, nick_name from member where login_name = ?
login_name, nick_name两个字段建立组合索引,比login_name简单索引要更快。

SQL优化

   分批处理: 不带分页参数的查询或者大量数据的update 和delete操作, 打散分批处理

    示例:

    业务描述: 更新用户过期的优惠券为不可用状态

    SQL语句:

  update status = 0 FROM conpon WHERE expire_date <= #{nowDate} and status =1 

  如果大量优惠券需要更新为不可用状态,执行上面的SQL可能会堵死其他SQL,分批处理伪代码如下:

 int pageNo = 1; int pageSize = 100;
   
 while (true) {
    List<Integer> batchIdList = queryList('select id FROM coupon WHERE expire_date <= #{nowDate}  and status = 1 limit #{(pageNo -1) *  pageSize}, #{pageSize}');
    if (CollectionUtils.isEmpty(batchIdList)){
      return; 
    }
   update('update status = 0 FROM conpon where status = 1 and id in #{batchIdList } ');
    pageNo ++;
 } 

  IN优化

  in适合做主表大子表小,EXTSIS 适合做主表小子表大.由于查询优化的不断升级,很多场景这两者性能差不多一样了.

/*查询会员用户下的订单id*/
SELECT id FROM orders WHERE user_id IN (SELECT id FROM user WHERE level = 'VIP') 
/*改为join连接*/
SELECT id FROM orders o INNER JOIN user u ON o.user_id = u.id WHERE u.level = 'VIP'

  不做列运算

  通常在查询条件列运算会导致索引失效

/*查询当日订单*/
SELECT id FROM order WHERE date_format (create_time, '%Y-%m-%d') = '2019-12-01';
/*date_format 这个函数会导致这个查询无法使用索引*/
SELECT id FROM order WHERE create_time BETWEEN '2019-12-01 00:00:00' AND '2019-12-01 23:59:59' 

  避免Select all

  如果不查询表中所有的列,避免使用SELECT * ,它会进行全表扫描, 不能有效的利用索引.

  JOIN 优化

  join的实现是采用Nested Loop Join算法,就是通过驱动表的结果集作为基础数据,通过该结数据作为过滤条件到下一个表中循环查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再次到后一个表中查询数据。

  驱动表和被驱动表尽可能增加查询条件,满足ON的条件而少用Where,用小结果集驱动大结果集。
  被驱动表的join字段上加上索引,无法建立索引的时候,设置足够的Join Buffer Size。
  禁止join连接三个以上的表,尝试增加冗余字段。

 

Guess you like

Origin www.cnblogs.com/shar-wang/p/11619899.html