Mysql

kubernetes部署mysql8

月盾

虽然很多文章说不建议将数据库部署在容器中,因为有性能问题。但我觉得这事还是要看具体使用场景来决定,而不是全盘否定。开发的过程中并不只有性能是最重要的,还有效率,易用性等也很重要。

对于测试环境来说,数据库部署在容器中肯定是可以的。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mysql
  name: mysql
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: mysql
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
      labels:
        app: mysql
    spec:
      containers:
      - env:
        - name: MYSQL_ROOT_PASSWORD
          value: xxx
        image: mysql:8.0.33
        imagePullPolicy: IfNotPresent
        name: mysql
        ports:
        - containerPort: 3306
          name: mysql
          protocol: TCP
        resources:
          limits:
            cpu: "4"
            memory: 8Gi
        volumeMounts:
        - mountPath: /var/lib/mysql
          name: data
        - mountPath: /etc/mysql/conf.d/
          name: mysql-config
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: mysql
      - configMap:
          defaultMode: 420
          name: mysql-config
        name: mysql-config

---

apiVersion: v1
kind: ConfigMap
data:
  my.cnf: |-
    [client]
    default-character-set = utf8mb4
    [mysql]
    default-character-set=utf8mb4
    [mysqld]
    character-set-server=utf8mb4
    collation_server=utf8mb4_unicode_ci
    gtid_mode=ON
    enforce_gtid_consistency=ON
    lower_case_table_names=1
    open_files_limit=65535
    slow_query_log = ON
    long_query_time = 2
    max_heap_table_size = 32M
    tmp_table_size = 2M
    log-bin = mysql-bin
    binlog_cache_size = 32K
    max_binlog_cache_size = 1G
    max_binlog_size = 1G
    binlog-format = ROW
    sync_binlog = 1
    log-slave-updates = 1
    expire_logs_days = 7
    default-time_zone = +8:00
    max_connect_errors = 65535
    max_allowed_packet = 536870912
    max_connections = 5120
    innodb_buffer_pool_instances = 1
    innodb_buffer_pool_size = 6442450944
    innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:15G
    server_id = 100
metadata:
  name: mysql-config

常用SQL审计平台介绍

月盾

数据安全一直是企业安全的重中之重,在企业系统开发过程中,数据库的安全日益增强,所以需要有个平台能够记录和审查数据库变更。

SQL 审计平台的功能特点:

  • 实时监控和记录:SQL 审计平台能够实时监听数据库操作,记录所有的 SQL 查询和事务操作,确保数据变更的可追溯性。
  • 用户行为分析:通过分析用户的查询行为和访问模式,SQL 审计平台可以识别风险操作、异常查询和异常登录行为,帮助提前发现潜在的安全威胁。
  • 合规报告与警报:SQL 审计平台能够生成详尽的合规报告,满足合规要求,并根据预设的规则触发警报,帮助管理员及时采取应对措施。
  • 数据完整性保护:通过审计日志记录的数据变更信息,SQL 审计平台能够帮助恢复受损的数据或进行调查取证,确保数据库的完整性和可靠性。
  • 权限管理与访问控制:SQL 审计平台提供丰富的权限管理功能,可以对用户进行细粒度的访问控制,确保只有经过授权的用户能够访问敏感数据。

常见的sql审计平台:

  • Yearning
  • Archery
  • bytebase

Yearning

官网:https://yearning.io

开发语言:golang

功能:

  • SQL 查询
    • 查询工单
    • 导出
    • 自动补全,智能提示
    • 查询语句审计
    • 查询结果脱敏
  • SQL 审核
    • 流程化工单
    • SQL语句语法检测
    • 根据规则检测SQL语句合规性
    • 自动生成DDL/DML回滚语句
    • 历史审核记录
  • 推送
    • E-mail 工单推送
    • 钉钉 webhook 机器人工单推送
  • 用户权限及管理
    • 角色划分
    • 基于用户的细粒度权限
    • 注册
  • 其他
    • todoList
    • LDAP 登录
    • 动态审核规则配置
    • 自定义审核层级
  • AutoTask 自动执行

部署

支持容器部署。

Archery

官网:https://archerydms.com/

开发语言:python

功能:

查询 审核 执行 备份 数据字典 慢日志 会话管理 账号管理 参数管理 数据归档
MySQL
MsSQL × × × × × × ×
Redis × × × × × × ×
PgSQL × × × × × × ×
Oracle × × × × ×
MongoDB × × × × × ×
Phoenix × × × × × × ×
ODPS × × × × × × × ×
ClickHouse × × × × × × × ×

SQL审核

MySQL实例

基于Inception/goInception实现,集成审核、执行、备份

linux修改MySQL 5.7.22字符集为utf8

月盾

网上也找了很多方案结果就是奇葩的不成功,最后直接修改/etc/mysql/mysql.conf.d/mysqld.cnf成功了。 在该文件最后添加

default-storage-engine=INNODB
character-set-server=utf8
collation-server=utf8_general_ci

重启成功。

这是本地虚拟机里的mysql

mysql> show variables like "character%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

完全正确,但是修改阿里云服务器以后还是有点小问题

character_set_database这一项还是latin1,不过似乎并不影响。 友情提示:纠正了mysql字符集发现新建的表还是latin1字符集,那有可能是该数据库本身的字符集就不对,可以试着看看。

读写数据库与读写文件哪个更快?

月盾

由于开发物流信息网,关于这个问题也是最近才想到的,就是到底读文件更快还是读数据库更快,能快多少,书生也搜索过,没见有网友就这个问题答复过, 也可能是太简单的缘故,我们本文还是来实测一下,由于时间关系,VC还没装,书生先用PHP测试了一下,下次有时间在C/C++上补充测试到本文来,因为 PHP的底层解析应该也是基于C的,所以估计两者环境测试结果差不多,小问题大收获,现在就来看一下测试过程及结果。

测试程序如下:

//说明1:由于读数据库语句调用简单的封包函数两次,所以把读文件也改成连续调用两次,数据库记录ID为1就在第一条,并且唯一索引。

//说明2:测试两次一次是4K数据,一次是整形数据

set_time_limit(0);
function fnGet($filename)
{
    $content = file_get_contents($filename);
    return $content;
}

function fnGetContent($filename)
{
    $content = fnGet($filename);
    return $content;
}
   
$times=100000;   
echo '数据库查询结果:<br/>';
//---------------------------------
$begin=fnGetMicroTime();
for($i=0;$i<$times;$i++)
{
    $res=$dbcon->mydb_query("SELECT log_Content FROM blog WHERE log_ID='1'");
    $row=$dbcon->mydb_fetch_row($res);
    $content=$row[0];
}
echo 'fetch_row '.$times.' 次时间:<font color=red>'.(fnGetMicroTime()-$begin).'</font>秒<br/>';
//---------------------------------

$begin=fnGetMicroTime();
for($i=0;$i<$times;$i++)
{
    $res=$dbcon->mydb_query("SELECT log_Content FROM blog WHERE log_ID='1'");
    $row=$dbcon->mydb_fetch_array($res);
    $content=$row['log_Content'];   
}
echo 'fetch_array '.$times.' 次时间:<font color=red>'.(fnGetMicroTime()-$begin).'</font>秒<br/>';
//---------------------------------

$begin=fnGetMicroTime();
for($i=0;$i<$times;$i++)
{
    $res=$dbcon->mydb_query("SELECT log_Content FROM blog WHERE log_ID='1'");
    $row=$dbcon->mydb_fetch_object($res);
    $content=$row->log_Content;   
}
echo 'fetch_object '.$times.' 次时间:<font color=red>'.(fnGetMicroTime()-$begin).'</font>秒<br/>';
//---------------------------------

$dbcon->mydb_free_results();
$dbcon->mydb_disconnect();

fnWriteCache('test.txt',$content);

echo '直接读文件测试结果:<br/>';

//---------------------------------
$begin=fnGetMicroTime();
for($i=0;$i<$times;$i++)
{
    $content = fnGetContent('test.txt');
}
echo 'file_get_contents直接读'.$times.'次时间:<font color=red>'.(fnGetMicroTime()-$begin).'</font>秒<br/>';
//---------------------------------

$begin=fnGetMicroTime();
for($i=0;$i<$times;$i++)
{
    $fname = 'test.txt';
    if(file_exists($fname))
     {
        $fp=fopen($fname,"r");//flock($fp,LOCK_EX);       
        $file_data=fread($fp, filesize($fname));//rewind($fp);      
        fclose($fp);
    }
    $content = fnGetContent('test.txt');
}   
echo 'fopen直接读'.$times.'次时间:<font color=red>'.(fnGetMicroTime()-$begin).'</font>秒<br/>';

结果:

4K大小数据的查询结果: fetch_row 100000 次时间:16.737720012665秒 fetch_array 100000 次时间:16.661195993423秒 fetch_object 100000 次时间:16.775065898895秒 直接读文件测试结果: file_get_contents直接读100000次时间:5.4631857872009秒 fopen直接读100000次时间:11.463611125946秒

数据表索引如何建立?多列索引还是单列索引

月盾

数据库优化第一想到的应该是建立索引,而且是最快速有效的优化方式,一般是对where子句中的字段建立索引,但是并不是越多越好,对于基数(区分度)越大的效果越好,比如唯一索引。对于一些表示状态的,比如值为0,1这类区分状态的字段就算数据再多索引的基数也很小,这类字段并不是非要加索引,加的索引越多越占磁盘空间,每次写入数据都要更新大量索引,反而成为累赘。但是不要以为真的没必要加,初学者对索引的认识浅薄,要么不加索引,要么在建表时就妄自推断加了很多索引。那么如何加索引才是正确的做法呢?

数据库中有一种是单列索引,一种是多列索引,要怎么加需要搞清楚这两者的区别,当查询条件有多个字段时,单列索引和多列索引有很大的区别。
如果使用多列索引,where条件中字段的顺序非常重要,需要满足最左前缀列。

最左前缀:查询条件中的所有字段需要从左边起按顺序出现在多列索引中,查询条件的字段数要小于等于多列索引的字段数,中间字段不能存在范围查询的字段(<,like等),这样的sql可以使用该多列索引。

mysql多列索引适合的场景

  1. 全字段匹配
  2. 匹配部分最左前缀
  3. 匹配第一列
  4. 匹配第一列范围查询(可用用like a%,但不能使用like %b)
  5. 精确匹配某一列和和范围匹配另外一列

order by操作中出现的字段同样适用于按值查找的规则,where+order by中出现的字段需可以建立满足如上五种规则多列索引。 使用多列需要按照最左索引列查找;不能跳过中间列;如果某一列是范围查询,那么其右边所有列无法使用索引。 IN什么情况下是范围查询,什么情况下是多个等值查询?如果有order by排序时,多个等于条件查询就是范围查询,没有order by排序就没有限制。 例如,建立多列索引(name, age, id), 只能使用索引的前两列。in是范围查询 … where name=“nginx.cn” and age in(15,16,17) order by id 可以使用整个索引,in是按值查询 … where name=“nginx.cn” and age in(15,16,17) and id =“3”

数据库优化一点总结

月盾

以前找工作的时候总被面试到数据库方面的知识,尤其是数据库优化。当然在去面试之前先补习一下,背一些网上的概念来应付。现在想想,要考察一个开发者数据库优化方面的知识只需要问一下有没有做过数据库设计和优化就行,如果做过相关工作那么多少会总结出来一些,如果没做过说出再多也是概念而已。

国庆节前韩豆咖派上线,然后这个节日就不会有好日子过了,上线三四天的时候很多用户反映帖子刷新不出来,登陆不了等问题,起初我以为是放假了大家回家网络不好导致的,后来测试了下接口花了一分多钟数据才返回,看来不是网络问题。查了下数据库帖子数量,居然达到6万了,想到以前背的概念,首先加索引试试,果然快了。但是节后数量达到12万的时候又出现了相同的问题,有点纳闷,索引页加了怎么还是慢呢?经过多次试验,分拆复杂查询后得出结论是由于查询语句中使用了left join自连接查询,通俗的说就是在12万数据中找出需要的数据,然后再在这12万中找出关联数据,光是这两个12万都够吓人了。最后还是把复杂的sql分解用程序控制查询子句,速度果然又提高了。

得出结论,一句复杂的sql不一定是最好的,分解成多句简单的sql可能有质的飞跃。这个方案在《高性能MYSQL》一书中也提到了,补充个图片:

但是对于sql查询到底该一次复杂查询还是多次简单查询没有明显界限,只有当一条复杂查询发现很慢的时候再分析慢的原因多次试验后就能知道哪个是最好的,而且复杂的sql也不利于优化,可能加了索引都没用,也不能使用查询缓存。当一条复杂的sql需要花3秒钟才能查出来的时候分拆的简单sql可能每秒可以查询5000次了.

MySQL查询当天0点,昨天

月盾

今天是

SELECT NOW();-- 2015-09-28 13:48:12

查询当天,格式为YYYY-MM-DD

SELECT CURDATE();-- 2015-09-28

查询当天,格式为YYYY-MM-DD HH:mm:ss

SELECT NOW();-- 2015-09-28 13:42:00

查询当天0点,格式为YYYY-MM-DD HH:mm:ss

SELECT DATE_FORMAT(CURDATE(),"%Y-%m-%d %H:%i:%s");-- 2015-09-28 00:00:00

查询当天早上9点,格式为YYYY-MM-DD HH:mm:ss

SELECT DATE_ADD(CURDATE(), INTERVAL 9 HOUR);-- 2015-09-28 09:00:00

查询昨天,格式为YYYY-MM-DD

SELECT DATE_SUB(CURDATE(),INTERVAL 1 DAY);-- 2015-09-27

查询昨天早上9点

SELECT DATE_ADD(DATE_SUB(CURDATE(),INTERVAL 1 DAY),INTERVAL 9 HOUR);-- 2015-09-27 09:00:00

DATE_ADD(date,INTERVAL expr type) 参数是合法的日期表达式。expr 参数是您希望增加的时间。

type 参数可以是下列值:

Type 值

MICROSECOND

SECOND

MINUTE

HOUR

DAY

WEEK

MONTH

QUARTER

YEAR

SECOND_MICROSECOND

MINUTE_MICROSECOND

MINUTE_SECOND

HOUR_MICROSECOND

HOUR_SECOND

HOUR_MINUTE

DAY_MICROSECOND

mysql一个字段为空时使用另一个字段排序

月盾

表中有两个日期字段createDate,updateDate。其中updateDate可以为空,要求使用updateDate排序,如果updateDate为空则使用createDate排序,结果要顺序排下来。

按照常规方法:

select * from table order by updateDate desc;

这样的结果是为空的数据排在了最下面,不符合要求。

这样试试:

select * from table order by updateDate desc, createDate desc;

这样排的结果是先按updateDate排序,updateDate为空的排在最下面,然后按createDate排序,这样也不符合要求。

正确方法:

select * from table order by IFNULL(updateDate, createDate) desc;

这种排序的结果是正确的,用ifnull函数判断updateDate如果为空的话就使用createDate排。