未做并发测试,但考虑了一下.可能有bug;
思路:n个数据表,一个数据关系表,关系表中得到数据表间关系;
显示
1表示表1,2表示表2
数据表名使用xx_下标
关系表只二列,id(即下标), 本表行数(可以考虑每次使用都查询而不是自己维护)
----
获取数据
/**
* 整站地址库
*/
public function index()
{
if (! $this->logined ){//未登录
return;
}
$this->load->library('pagination');
$tables = $this->db->query('SELECT * FROM email_tables ORDER BY id ASC');
if ($tables->num_rows()){
$tables = $tables->result_array();
$offset = (int)$this->uri->segment(4, 0);
$config['per_page'] = $pagePer = 5;
$count = 0;
$noEnd = 1;
$lists = array();
foreach ($tables as $table){
$rows = (int)$table['rows'];
if ($noEnd && (
( ($pagePer > 0) && ($offset < 1) ) //补足limit
|| ($offset < $rows) //首次
)
){//补足limit
$row = $this->db->select('*')
->from('email_'.$table['id'])
->where('id > ', 0)
->order_by('id ASC')
->limit($pagePer, $offset)
->get();
$getRows = $row->num_rows();
$lists[$table['id']] = $row->result_array();
if ($getRows < $pagePer){
$pagePer = $pagePer - $getRows;
}else{
$noEnd = 0;
}
}else if ($offset > 0){
$offset -= $rows;
}
$count += $rows;
}
$config['total_rows'] = $count;
$config['base_url'] = site_url("home/email/index/");
$this->pagination->initialize($config);
$data['pageCode'] = $this->pagination->create_links();
$data['lists'] = $lists;
}else{
$data['lists'] = null;
}
$this->load->view('home/email', $data);
}
显示模板
<table class="listTable" >
<tr>
<th>Id</th>
<th>收件人地址</th>
<th>检测次数</th>
<th>入库时间</th>
</tr>
<?php
foreach( $lists as $key => $tbl){
foreach ($tbl as $list){
echo "
<tr>
<td>{$key}:{$list['id']}</td>
<td>{$list['email']}</td>
<td>{$list['unexist']}</td>
<td>" .date('Y-m-d H:i:s', $list['time']). "</td>
</tr>
";
}
}
?>
<?php echo empty($pageCode)?"":'<tr><td colspan=4>'.$pageCode. '</td></tr>';?>
--------
删除
思路是,前台把各个表的列表(<input value="表下标.id" />)处理成:表下标.id_id,表下标.id_id格式后,php中再处理.
放在查询前就可以了
$del = $this->uri->segment(5, '');
if (FALSE !== strpos($del, 'del')){//删除
$del = str_replace('del', '', $del);
$del = explode(',', $del);//分解成表组
if ( empty($del)){
$data['tip'] = '错误id';
}else{
foreach ($del as $delTbl){
$delTbl = explode('.', $delTbl);//分离表,id
$delTbl[1] = explode('_', $delTbl[1]);//分离id
if (empty($delTbl[1])) continue;
$this->db->where_in('id', $delTbl[1]);
$this->db->delete('email_'.(int)$delTbl[0]);
$this->db->query('UPDATE email_tables SET rows = (SELECT COUNT(id) FROM email_' .(int)$delTbl[0]. ') WHERE id = ' .(int)$delTbl[0]);//更新记录条数,还是让数据库处理好点会比自己先查询再删除好.
$data['tip'] = "删除完成:{$delTbl[0]}:" .implode(',', $delTbl[1]) ."<br />";
}
}
}
---
插入
$tbls = $this->db->query('SELECT * FROM email_tables ORDER BY id ASC ' )->result_array();//取得所有表 ,主要 用于查询分表的 总 记录数,是否还可以插入
foreach ($tbls as $tbl){
$eid = $this->db->query('SELECT id FROM email_' .$tbl['id']. ' WHERE email=? limit 1', array($email) );//检测是否 存在时很 麻烦。需要 对 所有分表进行查询
if ($eid->num_rows()){//全站库存在
$eid = $eid->row()->id;
$existCount++;
break;
}else{
$eid = 0;
if ( empty($tblId) && ( (int)$tbl['rows'] < $maxRows) ) $tblId = $tbl['id'];//取得可插入记录表
}
}
if (empty($eid)){//插入全站库
if (empty($tblId)){//所有表已满,建立新表
$this->db->insert('email_tables', array('rows'=>0));
$tblId = $this->db->insert_id();
$this->db->query('DROP TABLE IF EXISTS email_' .$tblId);
$this->db->query("CREATE TABLE `email_{$tblId}` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(256) NOT NULL,
`unexist` int(2) NOT NULL DEFAULT '0',
`time` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;");//新表
}
$this->db->insert('email_' .$tblId, array('email'=>$email, 'time'=>time()) );
$this->db->query('UPDATE email_tables SET rows = rows + 1 WHERE id = ' .$tblId);
$eid = $this->db->insert_id();
$insertCount++;
$tblId = 0;//reset
}
-----------------
初设计,未 优化,有 bug,应该还可以进行 优化 ,像信箱地址索引,对于检测存在会节约时间;
还有,在 分页查询时,进行分表编号指定,相当于 limit于 某个分表,而不是分表 整体,虽然这样实现分页会导致前面数据 删除 后,分页从前算起和后算起 会不一至情况,但是要求不高时可以这 样,更加轻便点 ;
分表将导致表关系表非常的复杂,如有一 分组 表,使用到这个分表里面的数据做引用时,删除 /分页都会 非常的 麻烦.性能可能也会 下降 ,也就是说,如果需要执行整体处理的 时候,如整体的count,分表会带来麻烦,而 速度并不一定能 提高多少 ;
这只 是不打算 升级硬件而做的分表 处理 ,
并不是分表+分 区+集群的并发处理.
前者只是 尽量防止因为硬件性能过 差 载入过多 的 数据的处理而已.而它不是 并发处理;这只是相当数据库设计优化;
不是为了 引入更多的硬件提高服务性能;