MySQL之按年月分区

都说程序猿是靠爬坑积累起来的,对于这话深感认同。。。

最近公司新运行的项目,数据量已经过百万级了,为公司带来业绩、利润的同时,程序一些操作的耗时也越来越大,好吧,我承认这是前期着急上线,对于数据量的考量没有做到位,现在开始补救。。(开启填坑模式o(╯□╰)o)

在索引、字段类型已经建立好的情况下,将大表拆分
要对表的时间字段(类型:datetime)基于月进行分区。于是遍历MySQL官方文档分区章节,总结如下:

 
主要是以下几种:

1. RANGE分区
 
2. LIST分区
 
3. HASH分区

4. KEY分区

测试的维度主要从两个方面进行
 

 
针对特定的查询,是否能进行分区剪裁(即只查询相关的分区,而不是所有分区)
 
一、分区剪裁 
针对特定的查询,是否能进行分区剪裁(即只查询相关的分区,而不是所有分区)
 
二、查询时间
 
鉴于该批测试数据是静止的(即没有并发进行的insert,update和delete操作),数据量也不太大,从这个维度来考量貌似意义也不是很大。
 
因此,重点测试第一个维度。
 
基于RANGE的分区方案
 
在这里,选用了TO_DAYS函数


1、创建表并且设置按年月分区

CREATE TABLE bdm_range_datetime(
    id INT,
    hiredate DATETIME,
    time INT
)
PARTITION BY RANGE (TO_DAYS(hiredate) ) (
    PARTITION p1 VALUES LESS THAN ( TO_DAYS('20170101') ),
    PARTITION p2 VALUES LESS THAN ( TO_DAYS('20170201') ),
    PARTITION p3 VALUES LESS THAN ( TO_DAYS('20170301') ),
    PARTITION p4 VALUES LESS THAN ( TO_DAYS('20170401') ),
    PARTITION p5 VALUES LESS THAN ( TO_DAYS('20170501') ),
    PARTITION p6 VALUES LESS THAN ( TO_DAYS('20170601') ),
    PARTITION p7 VALUES LESS THAN ( TO_DAYS('20170701') ),
    PARTITION p8 VALUES LESS THAN ( TO_DAYS('20170801') ),
    PARTITION p9 VALUES LESS THAN ( TO_DAYS('20170901') ),
    PARTITION p10 VALUES LESS THAN ( TO_DAYS('20171001') )
);

1.png

2、批量插入10W条数据

public function ceshi(){
	for($i=0;$i<99999;$i++){
		$time = rand(1488297600, 1501430399);			//3月1日-7月30日
		$data['hiredate'] = date("Y-m-d H:i:s",$time);
		$data['time'] = time();
		$data['id'] = $i;
		M('range_datetime') -> add($data);
	}
}

2.png

3、查看各分区数据条数

SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'bdm_range_datetime';

4.png

4、查看特定查询语句的执行计划

explain partitions select * from bdm_range_datetime where hiredate > '20170501001000' and hiredate<='20170630235959';

3.png

从执行结果可以看出,查询2017年5月1日 - 2017年6月30日的数据,查询39623行,确实是走的所属分区,但是为什么会多走了p1这个分区呢??百思不得其解,查询了很多资料,还是没能找到答案,有知道原因的小伙伴可以在下方给我留言噢


==========华丽的分割线==========


TO_DAYS函数出现的这个p1分区没有解决的情况下,换了一种思路

基于RANGE COLUMNS的分区方案

RANGE COLUMNS可以直接基于列,而无需像上述RANGE那种,分区的对象只能为整数。


1、创建表并且设置按年月分区

CREATE TABLE bdm_range_datetime(
    id INT,
    hiredate DATETIME,
    time INT
)
PARTITION BY RANGE COLUMNS(hiredate) (
    PARTITION p1 VALUES LESS THAN ( '20170101' ),
    PARTITION p2 VALUES LESS THAN ( '20170201' ),
    PARTITION p3 VALUES LESS THAN ( '20170301' ),
    PARTITION p4 VALUES LESS THAN ( '20170401' ),
    PARTITION p5 VALUES LESS THAN ( '20170501' ),
    PARTITION p6 VALUES LESS THAN ( '20170601' ),
    PARTITION p7 VALUES LESS THAN ( '20170701' ),
    PARTITION p8 VALUES LESS THAN ( '20170801' ),
    PARTITION p9 VALUES LESS THAN ( '20170901' ),
    PARTITION p10 VALUES LESS THAN ('20171001' )
);

5.png

2、批量插入10W条数据

public function ceshi(){
	for($i=0;$i<99999;$i++){
		$time = rand(1488297600, 1501430399);			//3月1日-7月30日
		$data['hiredate'] = date("Y-m-d H:i:s",$time);
		$data['time'] = time();
		$data['id'] = $i;
		M('range_datetime') -> add($data);
	}
}

2.png

3、查看各分区数据条数

SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'bdm_range_datetime';

6.png

4、查看特定查询语句的执行计划

explain partitions select * from bdm_range_datetime where hiredate > '20170501001000' and hiredate<='20170630235959';

7.png


总结: 
1. 经过对比,个人倾向于第二种方案,即基于RANGE COLUMNS的分区实现。
 
2. 在5.7版本之前,对于DATA和DATETIME类型的列,如果要实现分区裁剪,只能使用YEAR() 和TO_DAYS()函数,在5.7版本中,又新增了TO_SECONDS()函数。
 
3. 其实LIST也能实现基于天的分区方案,但在这个需求上,相比于RANGE,还是显得很鸡肋。
 
4. TIMESTAMP类型的列,只能基于UNIX_TIMESTAMP函数进行分区,切记!


==========华丽的分割线==========

普通表转分区表

1、查看原表结构

desc bdm_order;

1.png

这是一张普通表,oid为主键


2、新增字段(datetime类型,用于分区)

2.png


3、修改原表结构(关联主键、索引)

3.png

4.png

设置关联主键,关联索引


4、将原普通表更改为分区表

alter table bdm_order partition by RANGE COLUMNS(hiredate) (
    PARTITION p201612 VALUES LESS THAN ( '20170101' ),
    PARTITION p201701 VALUES LESS THAN ( '20170201' ),
    PARTITION p201702 VALUES LESS THAN ( '20170301' ),
    PARTITION p201703 VALUES LESS THAN ( '20170401' ),
    PARTITION p201704 VALUES LESS THAN ( '20170501' ),
    PARTITION p201705 VALUES LESS THAN ( '20170601' ),
    PARTITION p201706 VALUES LESS THAN ( '20170701' ),
    PARTITION p201707 VALUES LESS THAN ( '20170801' ),
    PARTITION p201708 VALUES LESS THAN ( '20170901' ),
    PARTITION p201709 VALUES LESS THAN ( '20171001' ),
    PARTITION p201710 VALUES LESS THAN ( '20171101' ),
    PARTITION p201711 VALUES LESS THAN ( '20171201' ),
    PARTITION p201712 VALUES LESS THAN ( '20180101' ),
    PARTITION p201801 VALUES LESS THAN ( '20180201' ),
);

5.png


5、查看分区数据情况

SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'bdm_order';

6.png

从结果中看出,分区裁剪已经成功,所有数据都存在于2017年之前的分区中


6、将原time类型时间戳转换为可视化时间写入新增的字段中

UPDATE bdm_order SET hiredate=FROM_UNIXTIME(orderTime, '%Y-%m-%d %H:%i:%S') WHERE sid!=0;

7.png

8.png

从结果中看出,时间戳已经转换为可视化时间写到新字段中了


7、再次查看分区数据情况和查看特定查询语句的执行计划

SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'bdm_order';

9.png

explain partitions select * from bdm_order where hiredate > '20170501001000' and hiredate<='20170630235959';

10.png

至此填坑完毕!



客官,点击下方打赏一个呗~

Thinkphp关闭系统日志

题记:一大早正在吃早餐,工作群里有人发了张截图(如下图),说网站打不开了,马上丢下碗筷去处理。。。


1.jpg


原来是服务器磁盘空间不够了,可一想不对啊。。这只放框架文件,40个G怎么就不够了!?

2.png


好吧,连接Xshell,排查是哪些文件占用的系统磁盘空间!困...

命令:du -sh /*


3.png

4.png


一路排查下来,10个多G!!!原来是系统日志文件搞的鬼,果断删除!!!

删除之后,网站立刻恢复正常,整个世界都清净了!赶紧滚去继续吃早餐。。


事情到了这里还没完,既然这个日志文件是自动生成的,果断给他关闭掉

在index.php入口文件注释掉下面这句话

//define('APP_DEBUG',TRUE);

 5.png


然后去配置项那里增加一行参数

/*隐藏index.php主入口*/
'URL_CASE_INSENSITIVE'  =>	FALSE,

6.png


如果不设置这个配置项,本地运行没问题,但是到服务器会出现报错哟。。。


点击下方打赏一个呗~

【微信扫一扫】爬坑之旅,微信扫一扫调起摄像头

微信扫一扫功能在我们日常生活中很常见,那么微信JS-SDK是如何实现扫一扫功能的呢,最近在做一个线下扫码取货的功能,并附有代码实现。


查看微信官方JS-SDK文档,调起微信扫一扫的api


一:微信JS-SDK里面的接口都需要依赖js的config配置项,所以我们先获取配置项需要的参数

/**
 * 获取微信jsSDK配置项数据
 */
public function getWxConfig(){
	$mid = $_SESSION['userData']['mid'];
	
//	商户微信配置
	$wechat = M('wxtoken') -> where(['mid'=>$mid]) -> find();
	
//	签名生成时间戳
	$time = time();					//必须为数值类型,否则某些版本的的手机系统会报js的配置项有误!!
	
	$rand = rand(1000, 999999);		//签名随机串
	$rand = strval($rand);			//数值转字符串类型(如果不注意数据类型,只有安卓7.0能通过,其他版本的手机全部报js的配置项有误!!)
	
//	获取access_token
	$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$wechat['appid']."&secret=".$wechat['appsecret'];
	$get_access_token = $this -> https_request($url);
	$get_access_token = json_decode($get_access_token,TRUE);
	$access_token = $get_access_token['access_token'];
	
//	获取jsapi_ticket
	$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi";
	$get_jsapi_ticket = $this -> https_request($url);
	$get_jsapi_ticket = json_decode($get_jsapi_ticket,TRUE);
	$jsapi_ticket = $get_jsapi_ticket['ticket'];
	
//	config签名
	$jsConfigSign = "jsapi_ticket=".$jsapi_ticket.
				 "&noncestr=".$rand.							//签名的随机串类型必须是字符串
				 "&timestamp=".$time.							//签名的时间戳类型必须是数值
				 "&url=http://www.xxxxxxxxx.com/v/wxhx.html";	//该路径必须和拉起摄像头的页面路径完全一致(否则某些版本的手机js配置项报错)
	$jsConfigSign = sha1($jsConfigSign);
	
	$data['appid'] = $wechat['appid'];		//appid
	$data['timestamp'] = $time;				//生成签名的时间戳
	$data['nonceStr'] = $rand;				//生成签名的随机串
	$data['signature'] = $jsConfigSign;		//签名
	$data['jsapi'] = 'scanQRCode';			//jsApi
	
	echo json_encode($data,JSON_UNESCAPED_UNICODE);die;
}

QQ截图20170705100511.png

一开始只有华为荣耀8的手机才能成功拉起微信扫一扫,其他手机全部报错,都快把微信开发者文档泛滥了,也没找到原因,后来尝试了下把参数的类型都定义死了,居然所有手机都可以拉起扫一扫了。。。在此爬坑一下午,默默的鄙视下微信开发者文档的小编,文档无处不是坑。。


二:在页面js配置config配置项

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript"></script>	//微信js-sdk依赖文件
		<script type="text/javascript">
$.ajax({
	type:"post",
	url:"http://www.xxxxxxx.com/v_api/getWxConfig",
	dataType:'json',
	success:function(datas){
		
		wx.config({
		    debug: false, 		// 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
		    appId: datas.appid, 	// 必填,公众号的唯一标识
		    timestamp: datas.timestamp, // 必填,生成签名的时间戳
		    nonceStr: datas.nonceStr, 	// 必填,生成签名的随机串
		    signature: datas.signature,	// 必填,签名,见附录1
		    jsApiList: [datas.jsapi] 	// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
		});
		
		wx.ready(function(){
			wx.scanQRCode({
			    needResult: 1, 		    // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
			    scanType: ["qrCode","barCode"], // 可以指定扫二维码还是一维码,默认二者都有
			    success: function (res) {
				    var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
				    if (result!='') {
//				    	取到扫一扫返回结果后,在此编写后续的逻辑代码
				    }
				}
			});
		})
		
	}
});

QQ截图20170705101635.png

微信图片_20170705102117_meitu_1.jpg

微信扫一扫至此完结!耗时一天,再次默默的鄙视下微信开发者文档的小编。。。


点击下方打赏一个呗~

PHP调用barcodegen插件生成条形码

最近在为公司做一个扫码支付,需要用到条形码的相关功能,下面就先介绍如何生成条形码:


1、如何生成条形码?

复制下面的百度网盘链接,下载barcodegen插件

链接: https://pan.baidu.com/s/1o8nyfNG 

密码: r9c7


2、将下载出来的压缩包解压,并且放到ThinkPHP\Library\Vendor\barcodegen

2.1文件结构:

QQ截图20170625141505.png


2.2具体解析

(1)class文件夹是已封装好生成条形码的类,只需要调用即可。

(2)index.PHP是一个可选择条件生成条形码的功能,是主程序的入口,而html文件夹是提供的被引用的代码,code39.php指的是指向默认的编码格式。


3、在框架内调用插件

/**
	 * 生成付款条形码
	 */
	public function vip_get_barcode(){

		$file_dir = 'Uploads/Bar/'.date("Y-m-d",time());	//文件路径
        if(!file_exists($file_dir)) {					//判断文件是否存在
            mkdir($file_dir);						//不存在则生成
        }
		$imgUrl = $file_dir . '/' . time() . '.png';		//图片路径
        vendor('barcodegen.class.BCGcode128');				//载入依赖包
        vendor('barcodegen.class.BCGDrawing');
        vendor('barcodegen.class.BCGColor');
        $color_white = new \BCGColor(255, 255, 255);			//定义颜色
        $drawing = new \BCGDrawing('', $color_white);			//赋值颜色
        $code = new \BCGcode128();
        $font = new \BCGFontFile('Public/font/Arial.ttf', -1000); 	//字体大小
	$code->setFont($font);						//文字大小
	$code->setThickness(30);					//条码厚度
        $code->parse('123465789012345678');				//条形码内容
        $drawing->setBarcode($code);
        $rs = $drawing->setFilename($imgUrl);				//存放路径
        $drawing->draw();						//渲染图片
        $drawing->finish($drawing::IMG_FORMAT_PNG);			//生成图片
		
		$out_arr['code'] = '000000';
		$out_arr['url'] = $imgUrl;
		echo json_encode($out_arr,JSON_UNESCAPED_UNICODE);die;
	}

QQ截图20170625141820.png


4、将Ajax接到的路径输出到<img>标签的src里

QQ截图20170625142023.png

QQ截图20170625142342.png

爬坑两天,生成条形码业务逻辑完结。。。


点击下方打赏一个呗~


【微信支付】大道至简 抛弃SDK,纯原生开发之微信统一下单

前言:微信公众号的回调绑定了a服务器,我需要在b服务器做微信登录及支付,然后开启了无限爬坑模式…


由于代码和注释有点多,就直接上截图了


1.png

2.png

3.png

至此,微信统一下单告一段落,接下来是拉起微信H5输入支付密码的页面了。。。当时在这爬了整整1天的坑


4.png


支付完成之后,微信回8连发调用上面定义的回调页面,具体可点击下面的链接查看

【微信支付】大道至简 抛弃SDK,纯原生开发之微信通知


点击下方打赏一个呗~

PHP fputcsv()高效导出大数据量Excel(CSV)

前端时间公司部门提出后台要增加数据导出,以方便他们统计业务数据,很多人使用的PHPExcel插件,这个插件能很方便快捷的达到导入导出的功能。。

有需要PHPExcel导出的可以点击下面的链接

ThinkPHP3.2.3接入PHPExcel1.8.0控件导出Excel报表文件处理方法


现在问题来了。。虽然Excel表格最高支持107W行,但是只要数据达到2W-3W的量,PHPExcel就显得有点无力了,经常卡死或者内存溢出,这种大数据量的导出如果换成PHP自带函数 fputcsv() 来实现的话,效率能有很大的提升

set_time_limit(0);
ini_set("memory_limit", "1024M");

//		导出到本地
header ( "Content-type:application/vnd.ms-excel" );
header ( "Content-Disposition:filename=".$sname."商品销售报表.csv" );
header ('Cache-Control: max-age=0');

$fp = fopen('php://output', 'a');					//打开PHP文件句柄,php://output 表示直接输出到浏览器

$head = ['商品名称','商品条码','商品分类','现有库存','销售数量','商品总价','实收金额'];		//定义标题

foreach ($head as $i => $v) {
    $head[$i] = iconv('utf-8', 'GB18030', $v);		//将中文标题转换编码,否则乱码
}

fputcsv($fp, $head);								//将标题名称通过fputcsv写到文件句柄

foreach ($data as $k => $v) {						//重组数组
	$rows[$k]['gname'] = $v['gname'];
	$rows[$k]['barcode'] = $v['barcode'];
	$rows[$k]['cname'] = $v['cname'];
	$rows[$k]['kc'] = '1';
	$rows[$k]['sl'] = $v['sl'];
	$rows[$k]['hj'] = round($v['hj'],2);
	$rows[$k]['ss'] = round($v['hj'],2);
}

$limit = 30000;
$num = 0;											//计数器
foreach ( $rows as $v ) {  							//循环数据
	$num++;

	if($num == $limit){
		ob_flush();			//释放内存
		flush();
	}
    $rows = array();
    foreach ( $v as $kk => $vv){
        $rs[$kk] = iconv('utf-8', 'GB18030', $vv);	//转译编码
    }
    fputcsv($fp, $rs);
}

321321.png

最后需要注意的是,无论是使用PHP内置函数还是使用PHPExcel做导出功能,都需要使用href跳转get传参的方式,如果是用Ajax异步传参的话会出现问题!!!


点击下方图标打赏一个呗~

前端媒体查询 之PX or EM or REM?

你是否思考过对于媒体查询你应该使用px,em还是rem?我也产生过同样的问题,并且目前为止,我还是没有明确的答案。

一年之前,我第一次创建 mappy-breakpoint 仓库时,我一直使用rem单位。之后一次和铜板的谈话之后,我开始转向使用em,因为我并没有发现两者之间的区别。

关于媒体查询,除了emrem,常用单位还有像素。自从现在所有浏览器存在像素缩放问题,我想知道像素是否还可以用于媒体查询。

这周,我打算弄明白两者之间的区别。

在开始这篇文章之前,我假设你已经知道了什么是emrem单位。如果你不知道的话,请查阅这篇文章。

基础实验

我想创建三个独立的<div>元素,一个用于px,一个用于em,一个用于rem。我给每个<div>元素添加一个背景色,便于区分。

.pixel { background: red; }.em { background: green; }.rem { background: blue; }

接下来,因为我们比较媒体查询单位,我在三个选择器上创建了一个min-width

当媒体查询被触发时,我决定降低元素的不透明度,这样我就可以立即看到他们之间的差异。下面是像素媒体查询的 CSS 样式:

.pixel {  background: red;  
  @media (min-width: 400px) {    opacity: 0.5
  }
}

接下来,我们就要弄清楚如何创建emrem单位。

在第一次实验中,如果所有条件都理想的话,我想要测试三个单位之间的差异。换句话说,没有以下情况下发生:

  • <html>中更改font-size

  • 用户放大。

  • 用户更改浏览器字体设置。

如果已经满足了以上理想的条件,我就可以想当然认为的16px == 1em == 1rem。那么 400px就等于25em25rem.

.pixel {  background: red;  
  @media (min-width: 400px) {    opacity: 0.5
  }
}
.em {  background: green;  
  // 400 ÷ 16 = 25
  @media (min-width: 25em) {    opacity: 0.5
  }
}
.rem {  background: blue;  
  // 400 ÷ 16 = 25
  @media (min-width: 25rem) {    opacity: 0.5
  }
}

如果三个媒体查询以相同的方式进行,我们应该就可以看到他们都准确的在 400px 触发

结果如下(我在每一个浏览器所测试的)。

1.gif

因为三个媒体查询在相同的断点处被触发,所以我们知道,这一阶段pxemrem之间并无差异.

建立基础实验后, 下一步是要测试在缺少以上理想条件的情况下,会出现什么情况。同样的,条件为:

  • <html>中更改font-size

  • 用户放大。

  • 用户更改浏览器字体设置。

让我们一个一个的去测试。

在HTML中更改Font-size

第一种情况是很普遍的。事实上,几乎所有的网页使用此方法在CSS中设置font-size默认值:

html { 
  // setting default font size 
  font-size: 200% 
}

这里,我在测试中选择将font-size设置为200%,这意味着我将1em1rem设置为了32px.如果emremfont-size改变的影响,他们将会在800px被触发。

如下是测试结果:所有的媒体查询在Chrome, Firefox 和 IE 11浏览器下均在400px被触发。

2.gif

这是正确的表现行为。emrem单位在HTML中不应受font-size的变化影响,因为他们是基于浏览器内部的font-size属性。

不幸的是,我们没在 Safari 上得到此完美的行为。它在800px时触发了rem媒体查询:(

3.gif

因为这种行为只发生在 Safari 浏览器中,我很想看看是否移动端 Safari也会出现此情况。实验证明,也会出现此现象。

所以,第一个场景已经证明,我们不应该使用rem媒体查询。然而,让我们继续把 rem 放在我们其余的实验中,看看是否会发生其他的事情。

用户放大

第二种情况也是十分常见的。如果你页面上的文本不足够大,用户可能会选择使用他们浏览器中内置的缩放功能来放大文本。

一个简短的说明:最初关于em的想法是因为当用户放大时,旧浏览器不能够更新像素值。在这方面,测试媒体查询单位时缩放将有助于回答这个问题,我们是否可以现在使用基于px的媒体查询。

4.gif

这个实验结果显示,Chrome,Firefox 和 IE 显示相同的行为。px单位查询在emrem查询时被同时触发。

5.gif

哈哈,你猜对了...Safari并不支持:(

6.gif

不幸的是,这意味着基于像素的媒体查询是不存在问题的。Safari浏览器不支持他们(除非你决定放弃 Safari?)。

现在,我们进行最后的实验,看看是否仍然会发生什么意外。

用户更改浏览器的Font值

许多开发商愿意相信,用户不会改变他们浏览器font-size的值,因为他们已经隐藏在 deeeep 的设置之中。

恩恩,如果这样子的话后果会很棒,因为所有用户都表示出此行为,我们就不需要做这个实验!:)

不幸的是,并没有数据证明用户不更改他们浏览器的font-sizes属性值,所以作为开发人员,我们仍然有责任考虑到我们网站的灵活性。

在这个实验中,我扩大了四个浏览器中的font-size属性值,并通过以下方式进行测试(如果你想跟随):

  • Chrome: 前往settingsshow advanced settingsweb-content.

  • Firefox: 前往preferencescontentfonts 和 colors.

  • Internet Explorer: 在page单击, 之后 text-size.

我想不出在何处设置字体大小的唯一浏览器是Safari。所以我用代理服务器代替。例如,我将最小的字体大小更改为大于16px的设置。如果你也要这样做,请转到preferencesadvancedacessibility.

这是唯一所有浏览器表现行为一致的测试:

7.gif

正如你所看到的,像素查询的触发要早于emrem查询。

这里没有出现任何bug。由于 px 是绝对单位,就会正确的执行。无论用户如何更改他们默认的font-size属性值,断点应维持在 400px处。

另一方面,emrem基于浏览器的font-size属性值。因此,当用户更改默认值时,应该更新其媒体查询的font-size设置。

所以,这里对于像素的痴迷者,我很抱歉打破你的泡沫幻想,但基于像素查询是行不通。

实验总结

正如你可以从上面实验中看出,在四个浏览器之间表现一致的唯一单位是em。除了emrem在 Safari 上发现的bug之外,其并不存在任何差异。

px媒体查询在三次实验的两次中均表现正常(再一次,除了Safari)。不幸的是,在第三个实验中,当用户更改默认的浏览器font-size值时,px媒体查询仍在400px被触发。

因此,我在这些实验后得出的结论是:使用em媒体查询.

如果您正在使用一个没有使用em媒体查询的库时,你应该让其开发人员查看这篇文章,让他们知道他们的代码影响。不然,可以参考基于emMappy-breakpointsBreakpoint-sass 或者 sass-mq 库。


MySQL FROM_UNIXTIME根据指定时间段分组获取数据

UNIX_TIMESTAMP 将时间输出为时间戳

1、无参数调用:UNIX_TIMESTAMP()

返回值:当前时间戳

例子:select UNIX_TIMESTAMP(); => 1494746052  (2017/5/14 15:14:12)

2、无参数调用:UNIX_TIMESTAMP(date)

例子:select UNIX_TIMESTAMP("2017-01-01"); => 1483200000  (2017/01/01 00:00:00)



FROM_UNIXTIME 格式化MYSQL时间戳函数

作用:将MySQL中以int(11)存储的时间以"YYYY-MM-DD HH-II-SS"的格式来显示

语法,FROM_UNIXTIME(time,"%Y-%m-%d %H:%i:%s")

比如统计每天销售时间段高峰期(以小时分组),数据库表存了一张订单记录表:create table table_name(id int primary key,time int(10));  time记录的是订单时间戳,以前的做法是,接收查询开始时间、查询结束时间,然后循环查询每天的注册数量,代码:

/* 查询2015-12-01 至 2015-12-14 */  
// 开始的时间戳  
$startUnix = 1494604800; // 2017-05-13 00:00:00  
// 结束的时间戳  
$endUnix = 1494777599;   // 2017-05-14 23:59:59  
for($i = $startUnix; $i < $endUnix; $i += 86400){  // 86400为1天的秒数  
    // 查询  
    $sql = 'select count(*) from table_name where time> '.$i.' and register_time <= '.$i + 86400;  
    // 执行查询  
}

这种方法的弊端就是,查询开始于结束的日期相差多少天就查询检索数据库多少次。

优化方法:

/* 查询2017-05-13 至 2017-05-14 */  
// 开始的时间戳  
$startUnix = 1494604800; // 2017-05-13 00:00:00  
// 结束的时间戳  
$endUnix = 1494777599;   // 2017-05-14 23:59:59 
  
$sql = 'select count(id) as count, FROM_UNIXTIME(time, '%H') as datetime from table_name where time> '.$startUnix.' and time <= '.$endUnix group by datetime;  
// 执行查询

1111111111.png


查询时把时间戳转成小时,最后group by 分组,得到每天每个小时段的订单数,查询数据库一次

QQ截图20170514150550.png

PHP:array_multisort()对多维数组重新排序

日常的工作中,PHP经常会需要对复杂的数据重新排序处理。

可以使用PHP的array_multisort()对多个数组或多维数组进行重新排序

关联(string)键名保持不变,但数字键名会被重新索引。 
输入数组被当成一个表的列并以行来排序——这类似于 SQL 的 ORDER BY 子句的功能。第一个数组是要排序的主要数组。数组中的行(值)比较为相同的话就按照下一个输入数组中相应值的大小来排序,依此类推。——这句话是理解此函数用法的关键。

第一个参数必须是一个数组。接下来的每个参数可以是数组或者是下面列出的排序标志。

排序顺序标志: 
■SORT_ASC - 按照上升顺序排序 
■SORT_DESC - 按照下降顺序排序

排序类型标志: 
■SORT_REGULAR - 将项目按照通常方法比较 
■SORT_NUMERIC - 将项目按照数值比较 
■SORT_STRING - 将项目按照字符串比较

每个数组之后不能指定两个同类的排序标志。每个数组后指定的排序标志仅对该数组有效 - 在此之前为默认值 SORT_ASC 和 SORT_REGULAR。

$num1 = array(3, 5, 4, 3);
$num2 = array(27, 50, 44, 78);
array_multisort($num1, SORT_ASC, $num2, SORT_DESC);
print_r($num1);
print_r($num2);
//result: Array ( [0] => 3 [1] => 3 [2] => 4 [3] => 5 ) Array ( [0] => 78 [1] => 27 [2] => 44 [3] => 50 )

对多维数组(以二位数组为例)进行排序:

先看下结果(左边是未排序之前的数组,右边是排序过后的数组,按照price从大到小排序)

QQ截图20170508104853.png


下面是排序处理源码,最终得到上图的排序结果

	foreach ($out_arr['data'] as $k => $v) {
		$arr[] = $v['son']['price'];			//将需要排序的字段压入空数组
	}
			
	array_multisort($arr,SORT_DESC,SORT_NUMERIC,$out_arr['data']);
//	参数:1.排序数据,2.排序方式,3将每一项按数字顺序排列,4.数据源

QQ截图20170508105532.png