1. shm硬盘
先来说说临时表的概念。 临时表顾名思义,就是临时的,用完销毁掉的表。 数据既可以保存在临时的文件系统上,也可以保存在固定的磁盘文件系统上。 临时表有下面几种:
1全局临时表
这种临时表从数据库实例启动后开始生效,在数据库实例销毁后失效。在MySQL里面这种临时表对应的是内存表,即memory引擎。
2会话级别临时表
这种临时表在用户登录系统成功后生效,在用户退出时失效。在MySQL里的临时表指的就是以 create temporary table 这样的关键词创建的表。
3事务级别临时表
这种临时表在事务开始时生效,事务提交或者回滚后失效。 在MySQL里面没有这种临时表,必须利用会话级别的临时表间接实现。
4检索级别临时表
这种临时表在SQL语句执行之间产生,执行完毕后失效。 在MySQL里面这种临时表不是很固定,跟随MySQL默认存储引擎来变化。比如默认存储引擎是MyISAM,临时表的引擎就是MyISAM,并且文件生成形式以及数据运作形式和MyISAM一样,只是数据保存在内存里;如果默认引擎是INNODB,那么临时表的引擎就是INNODB,此时它的所有信息都保存在共享表空间ibdata里面。
MySQL 5.7对于InnoDB存储引擎的临时表空间做了优化。在MySQL 5.7之前,INNODB引擎的临时表都保存在ibdata里面,而ibdata的贪婪式磁盘占用导致临时表的创建与删除对其他正常表产生非常大的性能影响。在MySQL5.7中,对于临时表做了下面两个重要方面的优化:
MySQL5.7 把临时表的数据以及回滚信息(仅限于未压缩表)从共享表空间里面剥离出来,形成自己单独的表空间,参数为innodb_temp_data_file_path。
在MySQL5.7 中把临时表的相关检索信息保存在系统信息表中:information_schema.innodb_temp_table_info. 而MySQL 5.7之前的版本想要查看临时表的系统信息是没有太好的办法。
需要注意的一点就是,虽然INNODB临时表有自己的表空间,但是目前还不能自己定义临时表空间文件的保存路径,只能是继承innodb_data_home_dir。此时如果想要拿其他的磁盘,比如内存盘来充当临时表空间的保存地址,只能用老办法,做软链。举个小例子:
我现在用的OS是 Ubuntu12.X,想用tmpfs文件系统充当临时表空间,
root@ytt-master-VirtualBox:/usr/local/mysql/data# ln -s/run/shm/ /usr/local/mysql/data/tmp_space2
root@ytt-master-VirtualBox:/usr/local/mysql/data#ls -l | grep 'shm'
lrwxrwxrwx1 root root 9 Nov 13 10:28tmp_space2 -> /run/shm/
然后把
innodb_temp_data_file_path=tmp_space2/ibtmp2:200M:autoextend
添加到my.cnf里的[mysqld]下面一行
重启MySQL服务后,
mysql>select @@innodb_temp_data_file_path\G
***************************1. row ***************************
@@innodb_temp_data_file_path:tmp_space2/ibtmp2:200M:autoextend
1 rowin set (0.00 sec)
先写一个批量创建临时表的存储过程:
DELIMITER$$
USE`t_girl`$$
DROPPROCEDURE IF EXISTS `sp_create_temporary_table`$$
CREATEDEFINER=`root`@`localhost` PROCEDURE `sp_create_temporary_table`(
IN f_cnt INT UNSIGNED )
BEGIN
DECLARE i INT UNSIGNED DEFAULT 1;
WHILE i <= f_cnt
DO
SET @stmt = CONCAT('create temporarytable tmp',i,' ( id int, tmp_desc varchar(60));');
PREPARE s1 FROM @stmt;
EXECUTE s1;
SET i = i + 1;
END WHILE;
DROP PREPARE s1;
END$$
DELIMITER;
现在来创建10张临时表:
mysql>call sp_create_temporary_table(10);
QueryOK, 0 rows affected (0.07 sec)
如果在以前,我们只知道创建了10张临时表,但是只能凭记忆或者手工记录下来临时表的名字等信息。
现在可以直接从数据字典里面检索相关数据。
mysql> select * frominformation_schema.innodb_temp_table_info;
+----------+--------------+--------+-------+----------------------+---------------+
|TABLE_ID | NAME | N_COLS | SPACE| PER_TABLE_TABLESPACE | IS_COMPRESSED |
+----------+--------------+--------+-------+----------------------+---------------+
| 56 | #sql1705_2_9 | 5 | 36 | FALSE | FALSE |
| 55 | #sql1705_2_8 | 5 | 36 | FALSE |FALSE |
| 54 | #sql1705_2_7 | 5 | 36 | FALSE | FALSE |
| 53 | #sql1705_2_6 | 5 | 36 | FALSE | FALSE |
| 52 | #sql1705_2_5 | 5 | 36 | FALSE |FALSE |
| 51 | #sql1705_2_4 | 5 | 36 | FALSE | FALSE |
| 50 | #sql1705_2_3 | 5 | 36 | FALSE | FALSE |
| 49 | #sql1705_2_2 | 5 | 36 | FALSE |FALSE |
| 48 | #sql1705_2_1 | 5 | 36 | FALSE | FALSE |
| 47 | #sql1705_2_0 | 5 | 36 | FALSE | FALSE |
+----------+--------------+--------+-------+----------------------+---------------+
10rows in set (0.00 sec)
功能性我就写到这里,大家性能方面如果有兴趣可以找时间去测试。
2. shd硬盘
现在硬盘分机械硬盘和固态硬盘。两种硬盘工作机制不同,所以数据存储时间也不同,而且也受限于是静态放置还是保持使用状态。
简单说机械盘静态放置下数据可以存储10到15年,持续工作状态下3到5年(受限于硬盘自身寿命);固态盘不适合长时间静止,会有闪存颗粒电荷泄露问题,需要定期通电刷新,而且存储颗粒有读写次数限制,达到阈值后就坏了。
因此不管是什么硬盘是什么方式,都无法达到永久。因为,永久这个词太虚无,多久才能算是永久?
3. SHR硬盘
SHR全称 Synology Hybrid Raid,是群晖基于Linix LVM修改的逻辑分卷管理器,可以自动进行磁盘阵列的管理,SHR会自动使用磁盘空间的一部分用于数据校验,有一定的容错率,添加硬盘后也是自动管理的,多块容量不同的硬盘也能自动管理空间不至于和传统Raid一样按最小容量创建存储卷,能够最大化使用空间同时提高数据安全,按群晖自己的说法肯定是SHR有多好多好,创建磁盘时默认也是SHR,但如果了解RAID建议自己管理Raid,群晖自己也是这么说的:“ 对于专家用户,如果他们要手动管理 RAID 系统,建议使用传统 RAID 层级。以下手动 RAID 层级可在 Synology NAS 上使用: ”,所以你如果打算两块硬盘组建Raid,还是自己管理好,也不是很复杂,如果数据安全不是第一位的,希望最大化空间直接选Basic就好了。
4. shm内存
mysql> load data infile '/tmp/mytable.csv' into table mytable; load data infile肯定是最快的.
如果要用PHP来做,那可以考虑开启事务,批量插入,注意避免PHP执行超时. <?php
ignore_user_abort(true); //设置客户端断开连接时继续执行脚本
set_time_limit(0); //设置脚本最大执行时间,如果设置为0秒,则没有时间方面的限制.
//开启事务,批量插入
$db = new mysqli('127.0.0.1','user','pass','dbname',3306);
$db->query('SET AUTOCOMMIT=0');
$db->query('START TRANSACTION');
//导入CSV表格:CSV转数组
$fp = fopen('file.csv', 'r');
while( ($row = fgetcsv($fp)) !== FALSE ) {
//从文件指针中读入一行并解析CSV
$stmt = $db->prepare('INSERT INTO posts (id, post_title, post_content) VALUES (?,?,?)');
$stmt->bind_param('iss', $row[0], $row[1], $row[2]); //这里假设每行内容分别为ID,标题和内容
$stmt->execute();
//如果插入失败,改为更新
if($stmt->affected_rows == 0) {
$stmt = $db->prepare('UPDATE posts SET post_title = ?, post_content = ? WHERE id = ?');
$stmt->bind_param('ssi', $row[1], $row[2], $row[0]);
$stmt->execute();
if($stmt->affected_rows == 0) {
echo 'Import '.$row[0].' failed!'."\n";
}
}
}
fclose($fp);
//提交事务
$db->query('COMMIT'); //失败的操作已经echo输出来了,不需要回滚ROLLBACK
$db->query('SET AUTOCOMMIT=1');
$db->close();
Ubuntu(i5-3230M),开启事务时,PHP5(单进程)往SQLite插入100万条记录(38MB)只用16秒,平均每秒插入62500条.在/dev/shm内存中进行测试,PHP7耗时约9秒.
5. shm分区
如果是相同目录肯定是不可以,这样会照成写入冲突,不知道写到个文件夹 但是,如果你的第一个分区挂载点是 /1/2,第二个分区挂载点是/1/2/3就是可以的