现在的位置: 首页 > 综合 > 正文

MySQL的经典用法—-临时表与内存表

2018年05月28日 ⁄ 综合 ⁄ 共 11242字 ⁄ 字号 评论关闭

mysql5.5性能优化-内存表

临时表与内存表

内存表分为2种,但共同点是,重起数据库以后,内存中的数据全部丢失,内存表的功能有部分的限制,有些属性不能像正常表一样使用,所以请大家使用的时候谨慎参照官方文档.下面只是抛砖引玉. 
1.临时表:表建在内存里,数据在内存里 
2.内存表:表建在磁盘里,数据在内存里 
其中包括2个重要的参数 
[mysqld] 
# 内存表容量 
max_heap_table_size=1024M 
# 临时表容量 
tmp_table_size=1024M 

建立内存表的时候,在5.5里,需要指定表的引擎类型 ENGINE=MEMORY 
CREATE TABLE coldtest_vardata ( 
  Id int(11) AUTO_INCREMENT, 
  name varchar(255) 
) ENGINE=MEMORY DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT; 

临时表 
create temporary table tmp1(id int not null); 

其他常用参数 
# skip hostname,just use ip 
skip-name-resolve 

# auto start event 

event_scheduler=1


2
. Mysql 5.5 无法远程登陆:Can't get hostname for your address

错误信息:Can't
get hostname for your address 

修改配置文件 
在windows下面,文件时my.ini,在Linux下面是my.cnf 
解决方案是在 
[mysqld] 
skip-name-resolve                      #加上这一个属性 

它将禁止 MySql Server 对外部连接进行 DNS 解析,使用这一选项可以消除 MySql 进行 DNS 解析的时间。

但需要注意,如果开启该选项,则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求。

可以这么理解mysql处理客户端解析的过程:

1,当 mysql client 发起连接请求时,MySql Server 会主动去查 client 的主机名。

2,首先查找Windows系统目录下 /etc/hosts 文件,搜索域名和IP的对应关系。

3,如果hosts文件没有,则查找DNS设置,如果没有设置DNS服务器,会立刻返回失败;如果设置了DNS服务器,就进行反向解析,直到timeout。

注意:如果开启 skip-name-resolve 选项,要确认 MySql 是否采用过主机名的授权,

在 mysql 中运行如下命令:

mysql> select user,host from mysql.user where host <> 'localhost' ;

一般会得到以“%”授权(也就是任何地址)的记录:

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

| user             | host        |

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

| root             | %           |

| user_sync | 192.168.0.113 |

如果有host名是什么“DB1”“DB2”的,那么删除授权表中有 hostanme 的记录,然后重启mysqld。

3。mysql JDBC 驱动常用的有两个,一个是gjt(Giant
Java Tree)组织提供的mysql驱动,其JDBC Driver名称(JAVA类名)为:org.gjt.mm.mysql.Driver

详情请参见网站:http://www.gjt.org/另一个是mysql官方提供的JDBC Driver,其JAVA类名为:com.mysql.jdbc.Driver
驱动下载网址:http://dev.mysql.com/downloads/,进入其中的MySQL Connector/J区域下载。

mysql JDBC URL格式如下:
jdbc:mysql://[host:port]/[database][?参数名1][=参数值1][&参数名2][=参数值2]...

参数名称

参数说明

缺省值

最低版本要求

user

数据库用户名(用于连接数据库)

 

所有版本

password

用户密码(用于连接数据库)

 

所有版本

useUnicode

是否使用Unicode字符集,如果参数characterEncoding设置为gb2312或gbk,本参数值必须设置为true

false

1.1g

characterEncoding

当useUnicode设置为true时,指定字符编码。比如可设置为gb2312或gbk

false

1.1g

autoReconnect

当数据库连接异常中断时,是否自动重新连接?

false

1.1

autoReconnectForPools

是否使用针对数据库连接池的重连策略

false

3.1.3

failOverReadOnly

自动重连成功后,连接是否设置为只读

true

3.0.12

maxReconnects

autoReconnect设置为true时,重试连接的次数

3

1.1

initialTimeout

autoReconnect设置为true时,两次重连之间的时间间隔,单位:秒

2

1.1

connectTimeout

和数据库服务器建立socket连接时的超时,单位:毫秒。 0表示永不超时,适用于JDK 1.4及更高版本

0

3.0.1

socketTimeout

socket操作(读写)超时,单位:毫秒。0表示永不超时

0

3.0.1

对应中文环境,通常mysql连接URL可以设置为:
jdbc:mysql://localhost:3306/test?user=root&password=&useUnicode=true&characterEncoding=gbk&autoReconnect=true&failOverReadOnly=false

在使用数据库连接池的情况下,最好设置如下两个参数:
autoReconnect=true&failOverReadOnly=false

需要注意的是,在xml配置文件中,url中的&符号需要转义。比如在tomcat的server.xml中配置数据库连接池时,mysql jdbc url样例如下:
jdbc:mysql://localhost:3306/test?user=root&amp;password=&amp;useUnicode=true&amp;characterEncoding=gbk

4. Mysql 的定时备份过程

  mysql支持命令行导入导出数据文件,格式是*.sql 
1)导入: 
mysql -u用户名 -p密码 数据库名 < 文件路径\文件名 
2)导出: 
mysqldump -u用户名 -p密码 数据库名 > 文件路径\文件名 
3)真实案例 
本人是在windows 2003 开发服务器上,实现了定时自动备份 
一般文件名,用日期和时间.sql来使用.下面是我的*.bat批处理文件 
总共3行: 
第一行,表示切换到d盘 
第二行,找到mysql安装目录的bin目录,这样不需要设置环境变量 
第三行,导出*.sql文件,同时使用当前时间作为文件名,格式如下:cold_20101026_1244.sql,表示cold数据库,在2010年10月26日,中午12点44分生成的备份文件 
d: 
cd D:\Program Files\MySQL\MySQL Server 5.1\bin 
mysqldump -uroot -p123456 cold >  d:\mysql_data\cold_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%.sql 
然后,将该批处理文件,加到windows任务计划中, 
点击 控制面板>任务计划>添加任务计划。 
顺便给出还原代码,还原的时候要首先手工建立数据库,默认情况下,是不会自动创建数据库的 
d: 
cd D:\Program Files\MySQL\MySQL Server 5.1\bin 
mysql -uroot -p147258369 cold < D:\mysql_data\cold_20101026_1234.sql 

注:oracle的备份,也可以这么实现,跨平台也是如此,需要把脚本加到任务计划中来。 

5.mysql的性能优化使用技巧

在windows下,配置文件为%mysql_home%/my.ini

在linux下,配制文件为/etc/my.cnf

一 性能优化

    1--------INNODB_BUFFER_POOL_SIZE

    该参数是innodb引擎的最主要的性能参数,对数据库的性能起了决定性作用.说白了就是数据库的使用内存.

    2--------性能分析,

show status like '%'; #查看数据库状态

show variables like %; #查看数据库的变量
show engine innodb status\G; #查看innodb的监控状态

 

二 使用技巧

    1--------字符集尽量使用uft-8,这样更容易解决乱码问题,在linux下修改my.cnf的3处,修改前后可以通过命令

show variables like 'character%';

查看字符集状态.

    找到客户端配置[client] 在下面添加

    #默认字符集为utf8

    default-character-set=utf8
    在找到[mysqld] 添加

    #默认字符集为utf8
    default-character-set=utf8

    #设定连接mysql数据库时使用utf8编码,以让mysql数据库为utf8运行
    init_connect='SET NAMES utf8' 

6.mysql统计数据 ,但是空的数据也要显示

 在实际中,有这样一个需求,就是需要统计24个小时的相关数据.有的朋友认为简单的一句group by就可以解决。其实不然,真正的统计,24个小时都得有数据的,不允许出现缺失的现象.其实这个有点像废话,处理结果集ResultSet也可以,但为了减少JAVA的负担和增强java代码的可读性,所以尽量用SQL语句,一次性把数据处理好. 
表结构,有三个字段一看就明白 

Sql代码  收藏代码
  1. CREATE TABLE `vardata` (  
  2.   `Id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `namevarchar(255) DEFAULT NULL,  
  4.   `time` datetime DEFAULT '0000-00-00 00:00:00',  
  5.   `data` double(15,5) DEFAULT '0.00000',  
  6.   PRIMARY KEY (`Id`,`time`),  
  7.   UNIQUE KEY `unique` (`name`,`time`)  
  8. )  


    下面我想统计12个月的每月数据,如果数据存在,则显示数据;如果数据不存在,则现实我们约定的错误码(-601).下面只是给出了3条SQL语句提供样例.不管存不存在数据,肯定会查出3条记录来. 
    在真正的开发中,要把其中前面的time和后面where里的time,用所查询的语句,动态组装.如果朋友们还不理解,就给我留言吧 ^-^ 

Sql代码  收藏代码
  1. select if(count(*)=0,-601,data) as data,'2011-07-12 10:40:00' as time from vardata where time='2011-07-12 10:40:00'  
  2. union  
  3. select if(count(*)=0,-601,data) as data,'2012-08-12 10:40:00' as time from vardata where time='2012-08-12 10:40:00'  
  4. union  
  5. select if(count(*)=0,-601,data) as data,'2013-09-12 10:40:00' as time from vardata where time='2013-09-12 10:40:00';
     

7.mysql中动态sql语句的用法

在存储过程中,动态拼接一个字符串,然后执行之. 

Sql代码  收藏代码
  1. DROP PROCEDURE IF EXISTS demoSp;     
  2. CREATE PROCEDURE demoSp()  
  3. BEGIN  
  4.     set @sqlstr=concat("select count(*) from ""dual");  
  5.     prepare stmt from @sqlstr;  
  6.     EXECUTE stmt;           
  7.     deallocate prepare stmt;      
  8. END;  

8.mysql中的触发器

Sql代码  收藏代码
  1. CREATE TABLE `vardata` (  
  2.   `Id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `namevarchar(255) DEFAULT NULL,  
  4.   `time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',  
  5.   `data` double(15,5) DEFAULT '-601.00000',  
  6.   PRIMARY KEY (`Id`,`time`),  
  7.   UNIQUE KEY `unique` (`name`,`time`)  
  8. )  
  9.   
  10. CREATE TABLE `vardata_compute` (  
  11.   `Id` int(11) NOT NULL AUTO_INCREMENT,  
  12.   `namevarchar(255) DEFAULT NULL,  
  13.   `time` datetime DEFAULT NULL,  
  14.   `data` double(15,5) DEFAULT NULL,  
  15.   PRIMARY KEY (`Id`)  
  16. )   


Sql代码  收藏代码
  1. DROP TRIGGER IF EXISTS trigger_insert_59data;  
  2. CREATE TRIGGER trigger_insert_59data   
  3. AFTER INSERT   
  4. ON vardata   
  5. FOR EACH ROW   
  6. BEGIN  
  7.      DECLARE time_59 DateTime;                
  8.      SET time_59 = NEW.time-INTERVAL 1 SECOND;   
  9.      IF MINUTE(NEW.time)=0 AND SECOND(NEW.time)=0 THEN  
  10.         INSERT INTO vardata_compute SET name=NEW.name,time=time_59,data=NEW.data;    
  11.      END IF;     
  12. END;  
  13.   
  14. DROP TRIGGER IF EXISTS trigger_delete_59data;  
  15. CREATE TRIGGER trigger_delete_59data   
  16. AFTER DELETE   
  17. ON vardata   
  18. FOR EACH ROW   
  19. BEGIN  
  20.      DECLARE time_59 DateTime;       
  21.      SET time_59 = OLD.time-INTERVAL 1 SECOND;   
  22.      IF MINUTE(OLD.time)=0 AND SECOND(OLD.time)=0 THEN       
  23.         DELETE FROM vardata_compute WHERE time=time_59 AND name=old.name;  
  24.      END IF;     
  25. END;  
  26.   
  27. DROP TRIGGER IF EXISTS trigger_update_59data;  
  28. CREATE TRIGGER trigger_update_59data   
  29. AFTER UPDATE   
  30. ON vardata   
  31. FOR EACH ROW   
  32. BEGIN  
  33.      DECLARE time_59 DateTime;       
  34.      SET time_59 = NEW.time-INTERVAL 1 SECOND;   
  35.      IF MINUTE(NEW.time)=0 AND SECOND(NEW.time)=0 THEN            
  36.         UPDATE vardata_compute SET data=NEW.data WHERE time=time_59 AND name=NEW.name;  
  37.      END IF;     
  38. END;  

9.mysql中大幅度提高性能方案———分区表

工作中仍然是海量数据出现的情况.每年大概会有几亿条记录.而且数据的时效性比较强.但历史数据仍然要求保留.这个时候经过分析和研究,最终决定通过时间字段进行分区.下面是分区表的创建代码.读者门在插入了不同年份时间段以后,可以时间字段为条件进行查询,可以看到数据库扫描过的区段. 
Sql代码  收藏代码
  1. CREATE TABLE part_data  
  2.       (c1 int default NULL,  
  3.   c2 varchar(30) default NULL,  
  4.   c3 date default NULL)  
  5.   partition by range (to_days(c3))  
  6.  (PARTITION p0 VALUES LESS THAN (to_days('1995-01-01')),  
  7.  PARTITION p1 VALUES LESS THAN (to_days('1996-01-01')) ,  
  8.  PARTITION p2 VALUES LESS THAN (to_days('1997-01-01')) ,  
  9.  PARTITION p3 VALUES LESS THAN (to_days('1998-01-01')) ,  
  10.  PARTITION p4 VALUES LESS THAN (to_days('1999-01-01')) ,  
  11.  PARTITION p5 VALUES LESS THAN (to_days('2000-01-01')) ,  
  12.  PARTITION p6 VALUES LESS THAN (to_days('2001-01-01')) ,  
  13.  PARTITION p7 VALUES LESS THAN (to_days('2002-01-01')) ,  
  14.  PARTITION p8 VALUES LESS THAN (to_days('2003-01-01')) ,  
  15.  PARTITION p9 VALUES LESS THAN (to_days('2004-01-01')) ,  
  16.  PARTITION p10 VALUES LESS THAN (to_days('2010-01-01')),  
  17.  PARTITION p11 VALUES LESS THAN MAXVALUE );  



分区查询,可以查看扫描过的区段.当然要加上where子句,以c3时间为条件进行检索.若不使用时间字段,分区将失去作用. 

Sql代码  收藏代码
  1. explain partitions select * from part_data\G  

10.mysql中海量数据统计处理,模拟物化视图

一 物化视图 
    物化视图,它是用于预先计算并保存表连接或聚集等耗时较多的操作的结果,这样,在执行查询时,就可以避免进行这些耗时的操作,而从快速的得到结果。 
    只有大型数据库oracle10g,db2才支持这个功能,而MySQL5.1暂时还没有这个功能。本人通过事件调度和存储过程模拟了物化视图。下面大家一起来讨论吧。^-^ 

二 准备知识 
    1)存储过程:玩过数据库的人,都知道他是啥~,~ 
    2)事件调度:在MySQL5.1开始才有的新功能。说白了就是个定时器。跟java里的timer差不多。

Sql代码  收藏代码
  1. show processlist; --这个命令能是查看线程,如果启动了时间调度器,则会多个event_scheduler  
  2. set global event_scheduler = on--启动时间调度器,关闭就不用我说了吧,off就可以了  
  3. show processlist\G;--查看线程,是不是多了个 User: event_scheduler  
  4.   
  5. --如果想启动单个事件,则执行下面命令  
  6. ALTER EVENT `myEvent`   
  7. ON COMPLETION PRESERVE   
  8. ENABLE;  
  9. --关闭  
  10. ALTER EVENT `myEvent`   
  11. ON COMPLETION PRESERVE   
  12. DISABLE;  

mysql默认不会启动event,所以需要修改你的my.ini或my.cnf[mysqld]的下面加入如下行

event_scheduler=1

三 模拟物化视图 
    1)先建个基表吧。

Sql代码  收藏代码
  1. CREATE TABLE `user` (  
  2.   `Id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `namevarchar(255) DEFAULT NULL,  
  4.   `age` int(11) DEFAULT NULL,  
  5.   PRIMARY KEY (`Id`)  
  6. );  

    2)设计视图 
我想查询所有18岁员工的数量。 
很简单,select count(*) from user where age=18; 
如果是传统概念的视图,在MySQL中,每次访问视图的时候,他都会创建个临时表,然后执行一次。在海量数据的情况下,这样的效率是非常低的。而物化视图,则他会定时去刷新这个临时表,而不是你在用的时候才会去刷新。并且物化视图的"临时表"是一直存在的。所以效率高出非常多。拿空间换时间^-^ 

    3)创建"物化视图"的表

Sql代码  收藏代码
  1. CREATE TABLE `user_view` (  
  2.   `Id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `c` int(11) DEFAULT NULL,  
  4.   PRIMARY KEY (`Id`)  
  5. );  


    4)设计存储过程

Sql代码  收藏代码
  1. CREATE PROCEDURE demoSp()  
  2. BEGIN  
  3.     DECLARE z INT;  
  4. SELECT COUNT(*) INTO z FROM user;  
  5. delete from user_view;  
  6. insert into user_view(c) values(z);  
  7. END;  

    5)设计调度并执行,为了使实验明显,我就把调度设置成5秒一次吧。周期可以自己调节。

Sql代码  收藏代码
  1. CREATE EVENT `myEvent`   
  2. ON SCHEDULE EVERY 5 SECOND   
  3. ON COMPLETION PRESERVE   
  4. DO call demoSp();  

四 总结 
    上面的实现,可能不太明显,但在海量数据处理的时候进行统计,性能有明显的提升。大家做实验的时候,可以增加一个insert语句,方便观察。在更新数据的时候,如果数据量大,则需要按下面步骤来处理 
1)delete 1条记录 
2)insert 1条记录 
3)提交 
    如果一次性把数据全部删除,在查询的时候,有可能会出现空表的现象。而且会影响统计使用。 
    通过利用这个事件调度,定时备份的事情也同时解决了.

    建议大家配合表分区,索引同时使用,这样可以提高性能.

未完成:在更新表的时候,需要采用某种算法来执行,这样才能提高性能,而不是单纯的删除再插入.

11.mysql中按月统计数据

   表finance有俩个字段如下 
date date 
money double(15,2) 
    下面需要对表finance的2010年财务数据,按月进行统计 

Sql代码  收藏代码
  1. select DATE_FORMAT(date,'%Y-%m'as month,sum(money) as money   
  2. from finance   
  3. where DATE_FORMAT(date,'%Y')=2010   
  4. group by month   
  5. order by month  


    下面是按周统计 
查看MySQL的manual 
%X Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V 
%x Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v 
    其中 
1如果周一为一周的第一天,则(小写) DATE_FORMAT(date,'%x %v') 
2如果周日为一周的第一天,则(大写) DATE_FORMAT(date,'%X %V') 

Sql代码  收藏代码
  1. select DATE_FORMAT(date,'%x年-第%v周'as week,sum(money) as money   
  2. from finance_base   
  3. where DATE_FORMAT(date,'%Y')=2010   
  4. group by week  

12.mysql中数据的重复判断

工作中的实际应用.在采集数据的时候,要求数据采集以后,不能重复.同时也要求有多个实例同时运转,保证数据采集的连续性.因此总结了一下,做成了如下的小试验.核心代码如下: 
表结构:只有3个字段 
id,name,password 
Sql代码  收藏代码
  1. CREATE TABLE `tt` (  
  2.   `Id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `namevarchar(255) DEFAULT NULL,  
  4.   `passwordvarchar(255) DEFAULT NULL,  
  5.   PRIMARY KEY (`Id`)  
  6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  



sql语句 
1)推荐 

Sql代码  收藏代码
  1. insert ignore into tt(name,passwordvalues('phl','123')  


2)不推荐,因为insert的时候select,会锁定select的表 

Sql代码  收藏代码
  1. insert into tt(name,passwordselect 'phl','123' from dual where not exists(select * from tt where name='phl' and password='123')  



这个SQL语句的含义是,如果插入的数据 name='phl',password='123'不存在,则执行插入; 

补充: 
方法1里面,之所以没有过滤。是因为没有建立name与password的联合主建;


13.

抱歉!评论已关闭.