如果mysql里面的数据过多,查询太慢怎么办?

如果mysql里面的数据过多,查询太慢怎么办?,第1张

问题

我们有一个 SQL,用于找到没有主键 / 唯一键的表,但是在 MySQL 5.7 上运行特别慢,怎么办?

实验

我们搭建一个 MySQL 5.7 的环境,此处省略搭建步骤。

写个简单的脚本,制造一批带主键和不带主键的表:

执行一下脚本:

现在执行以下 SQL 看看效果:

...

执行了 16.80s,感觉是非常慢了。

现在用一下 DBA 三板斧,看看执行计划:

感觉有点惨,由于 information_schema.columns 是元数据表,没有必要的统计信息。

那我们来 show warnings 看看 MySQL 改写后的 SQL:

我们格式化一下 SQL:

可以看到 MySQL 将

select from A where A.x not in (select x from B) //非关联子查询

转换成了

select from A where not exists (select 1 from B where B.x = a.x) //关联子查询

如果我们自己是 MySQL,在执行非关联子查询时,可以使用很简单的策略:

select from A where A.x not in (select x from B where ...) //非关联子查询:1. 扫描 B 表中的所有记录,找到满足条件的记录,存放在临时表 C 中,建好索引2. 扫描 A 表中的记录,与临时表 C 中的记录进行比对,直接在索引里比对,

而关联子查询就需要循环迭代:

select from A where not exists (select 1 from B where B.x = a.x and ...) //关联子查询扫描 A 表的每一条记录 rA:     扫描 B 表,找到其中的第一条满足 rA 条件的记录。

显然,关联子查询的扫描成本会高于非关联子查询。

我们希望 MySQL 能先"缓存"子查询的结果(缓存这一步叫物化,MATERIALIZATION),但MySQL 认为不缓存更快,我们就需要给予 MySQL 一定指导。

...

可以看到执行时间变成了 0.67s。

整理

我们诊断的关键点如下:

\1. 对于 information_schema 中的元数据表,执行计划不能提供有效信息。

\2. 通过查看 MySQL 改写后的 SQL,我们猜测了优化器发生了误判。

\3. 我们增加了 hint,指导 MySQL 正确进行优化判断。

但目前我们的实验仅限于猜测,猜中了万事大吉,猜不中就无法做出好的诊断。

Mysql常见的几个错误问题及解决方法:

1.问题: mysql DNS反解:skip-name-resolve

错误日志有类似警告:

120119 16:26:04 [Warning] IP address '192.168.1.10' could not be resolved: Name or service not known

120119 16:26:04 [Warning] IP address '192.168.1.14' could not be resolved: Name or service not known

120119 16:26:04 [Warning] IP address '192.168.1.17' could not be resolved: Name or service not known

通过show processlist发现大量类似如下的连接:

|592|unauthenticated user|192.168.1.10:35320|NULL|Connect| |login|NULL|

|593|unauthenticated user|192.168.1.14:35321|NULL|Connect| |login|NULL|

|594|unauthenticated user|192.168.1.17:35322|NULL|Connect| |login|NULL|

skip-name-resolve 参数的作用:不再进行反解析(ip不反解成域名),这样可以加快数据库的反应时间。

修改配置文件添加并需要重启:

[mysqld]

skip-name-resolve

2.问题错误日志:Error: Can't create a new thread (errno 12)

数据库服务器问题,数据库 *** 作无法创建新线程。一般是有以下3个方面的原因:

1)、MySQL 线程开得太多。

2)、服务器系统内存溢出。

3)、环境软件损坏或系统损坏。

【问题解决】

1)进入 phpmyadmin 的 mysql 数据库中的 user 表,对数据库的用户进行编辑,修改 max_connections 的值。适当的改小一点。

2)联系服务器管理员检查服务器的内存和系统是否正常,如果服务器内存紧张,请检查一下哪些进程消耗了服务器的内存,同时考虑是否增加服务器的内存来提高整个系统的负载能力。

3)mysql版本更改为稳定版本

4)优化网站程序的sql等等

3. *** 作报错:ERROR 1010 (HY000): Error dropping database

mysql>drop database xjtrace

ERROR 1010 (HY000): Error dropping database (can't rmdir './xjtrace/

在做数据库删除时出现这种提示,其原因是在database下面含有自己放进去的文件,譬如*.txt文件或*.sql文件等,只要进去把这个文件删了在执行。

mysql>drop database xjtrace

Query OK, 0 rows affected (0.00 sec)

果断删除即可!!

4.导出数据很快,导入到新库时却很慢:

MySQL导出的SQL语句在导入时有可能会非常非常慢,经历过导入仅400万条记录,竟用了近2个小时。在导出时合理使用几个参数,可以大大加快导入的速度。

-e 使用包括几个VALUES列表的多行INSERT语法

--max_allowed_packet=XXX 客户端/服务器之间通信的缓存区的最大大小

--net_buffer_length=XXX TCP/IP和套接字通信缓冲区大小,创建长度达net_buffer_length的行

注意:max_allowed_packet和net_buffer_length不能比目标数据库的配置数值大,否则可能出错。

首先确定目标库的参数值

mysql>show variables like 'max_allowed_packet'

+--------------------+---------+

| Variable_name | Value |

+--------------------+---------+

| max_allowed_packet | 1048576 |

+--------------------+---------+

1 row in set (0.00 sec)

mysql>show variables like 'net_buffer_length'

+-------------------+-------+

| Variable_name | Value |

+-------------------+-------+

| net_buffer_length | 16384 |

+-------------------+-------+

1 row in set (0.00 sec)

根据参数值书写mysqldump命令,如:

mysql>mysqldump -uroot -p 数据库名 -e --max_allowed_packet=1048576 -net_buffer_length=16384 >SQL文件

例如:

mysql>mysqldump -uroot -p xjtrace -e --max_allowed_packet=1048576 --net_buffer_length=16384 >xjtrace_data_`date +%F`.sql

之前2小时才能导入的sql现在几十秒就可以完成了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/7275062.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-03
下一篇 2023-04-03

发表评论

登录后才能评论

评论列表(0条)

保存