반응형
간단한 메모리 테이블 MemoryTable
주요 기능:
우리가 어떤 집합내의 데이터를 순회하거나 고주파도로 조회해야 할 때, 매번 데이터 테이블에서 찾는다면, 사이클 횟수가 증가함에 따라 소요시간이 직선적으로 증가할 수 있는데, 이때 우리가 할 수 있는 최적화는 먼저 순회하고자 하는 데이터 집합을 찾아낸 다음, 메모리 중에서 순회하여 필요한 데이터를 선별하는 것인데, 이 메모리 테이블은 바로 이 용도이다.
주로 실현하다
주요 목적:
메모리 테이블을 조작할 때 데이터베이스를 조작하는 것과 같이 연쇄적으로 호출할 수 있고, 간단하고 편리하기를 바란다.
예: table->where->order->limit->select( );
여기서는 field, where, order, limit, find, select에서 흔히 사용하는 방법을 간단하게 구현하였다.
코드 구현
<?php
/**
*/
use think\Exception;
/**
* Class MemoryTable
* creator 0505
* 메모리 테이블은, 주로 테이블의 일부 데이터를 자주 찾을 때의 캐시 처리에 사용된다
*/
class MemoryTable
{
protected $data=[];//데이터 시트에서 찾아낸 메타데이터
protected $fields=[];//필드
protected $whereCallable=null;
protected $limit=0;
protected $offset=0;
protected $orderWay=[];
protected $orderField=[];
public function __construct(array $data)
{
$this->data=$data;
}
public function __destruct()
{
$this->clear();
}
//오래된 데이터를 정리하다
private function clear(){
$this->data=[];
$this->fields=[];
$this->whereCallable=null;
$this->limit=0;
$this->offset=0;
$this->orderWay=[];
$this->orderField=[];
}
public function setData(array $data){
$this->clear();
$this->data=$data;
return $this;
}
public function getData(){
return $this->data;
}
/**
* 기존의 where 스크리닝 방법을 대체하여 콜백으로 통일하여 간편하고 실용적
* @param callable $callable,선별 콜백 함수
* @return $this
*/
public function whereCall(callable $callable){
$this->whereCallable=$callable;
return $this;
}
public function limit(int $limit,int $offset=0){
$this->limit=$limit;
$this->offset=$offset;
return $this;
}
/**
* @param string $field ,일시적으로 최대 3개의 필드를 지원하며, 이후 필드는 유효하지 않습니다 "id desc,name asc,age asc"
* @return $this
* @throws Exception
*/
public function order(string $field){
$tempFields=[$field];
if (strpos($field,','!==false)){
$tempFields=explode(',',$field);
}
$this->orderField=[];
$this->orderWay=[];
foreach ($tempFields as $tempField) {
if (strpos($tempField,' '===false)){
throw new Exception("필드 형식 오류");
}
//여러 개의 공백 제거
while (strpos($tempField,' '!==false)){
str_replace(' ',' ',$tempField);
}
$tempField=explode(' ',$tempField);
$this->orderField[]=$tempField[0];
$this->orderWay[]=$tempField[1];
}
return $this;
}
public function field(string $field){
if (!empty($field)){
$this->fields=explode(',',$field);
}
return $this;
}
public function find(callable $callable=null){
$this->limit=1;
$this->offset=0;
return $this->select($callable);
}
/**
* @param callable|null $callable,where조건판단 콜백 함수
* @return array
*/
public function select(callable $callable=null){
if (empty($this->data)||!is_array($this->data)){
return [];
}
if (!empty($callable)){
$this->whereCall($callable);
}
if (!empty($this->data)){
$selectData=[];
foreach ($this->data as $item) {
$selectItem=call_user_func($this->whereCallable,$item);
if (!empty($selectItem)){
//필드 필터 여부
if (!empty($this->fields)&&!in_array('*',$this->fields)){
$newItem=[];
foreach ($this->fields as $field) {
$newItem[$field]=$selectItem[$field];
}
$selectItem=$newItem;
}
$selectData[]=$selectItem;
}
}
//판단순서
if (!empty($this->orderField)){
$selectData= $this->arraySort($selectData,$this->orderField,$this->orderWay);
}
//절취하다
if ($this->limit>0){
$selectData=array_slice($selectData,$this->offset,$this->limit);
}
//데이터 비우기
$this->clear();
return $selectData;
}
}
//배열 정렬, 일시적으로 최대 3개의 필드 지원
public function arraySort(array &$data,array $fields,array $way){
if (empty($data)||empty($fields)||empty($way)||count($fields)!=count($way)){
return false;
}
foreach ($way as &$item) {
if ($item == 'ASC' || $item == 'asc') {
$item = SORT_ASC;
} else {
$item = SORT_DESC;
}
}
if (count($fields)>=3){
array_multisort(array_column($data,$fields[0]),$way[0],array_column($data,$fields[1]),$way[1],array_column($data,$fields[2]),$way[2],$data);
}elseif (count($fields)==2){
array_multisort(array_column($data,$fields[0]),$way[0],array_column($data,$fields[1]),$way[1],$data);
}elseif (count($fields)==1){
array_multisort(array_column($data,$fields[0]),$way[0],$data);
}
return $data;
}
}
사용 & 테스트
테스트 코드 비즈니스 논리:
우리는 어떤 회의 하의 모든 주문서의 구체적인 참가증 및 참가증 인원수, 출석체크 등의 데이터를 집계해야 하기 때문에, 일반적인 조작은 먼저 지정된 회의 하의 모든 주문서를 찾아낸 다음, 주문 번호를 통해 하나하나 집적하는데 필요한 데이터를 찾는 것이다
public function doTest( ){
//미팅을 통해 모든 주문 데이터 찾기
$data=model("MeetOrderQrcode")->where("meet_id"=>9211])->group("order_id")->field("id,order_id")->select(;);
// 총 테스트 데이터 출력량
echo "총 데이터 볼륨 =.count($data)". </br>;
//시작시간 기록
echo "start_time=.microtime(true)". </br>;
//1: 전통적인 표 찾기 방법
foreach ($data as $dataum) {
//선별조건은 회의 id=9211&주문번호=통과된 스파이크번호이며, 상태가 원하는 상태의 모든 참가증 데이터는 id 역순에 따라
$d1= model("MeetOrderQrcode")->where("meet_id"=>9211, "order_id"=>$datum["order_id"], "status"=>["in", "0,1,2,3"]])->order("id desc")->select(;);
// 이게 바로 주문 데이터 찾기
$d2=model('MeetOrder')->where(['meet_id'=>9211, 'order_id'=>$datum['order_id'], 'status'=>['in', '0,1,2,3'])->order('id desc')->select(;);
//뒤에 있는 다른 집합은 쓰지 않습니다...
}
// 메모리 캐시 테이블 사용 시간 시작
echo " finish_time=.microtime(true)". </br>;
// 회의 ID로 메모리 테이블에 필요한 캐시 데이터 찾기
$selectData=model("MeetOrderQrcode")->where(['meet_id'=>9211])->select(;
$selectData2=model("MeetOrder")->where(['meet_id'=>9211])->select(;)
// 메모리 테이블 초기화
$table=new MemoryTable($select Data);
$table2=new MemoryTable($select Data2);
//2: 메모리 테이블 MemoryTale을 통해 데이터를 찾아보니 위의 1의 결과와 일치합니다.
foreach ($data as $dataum) {
//이것은 데이터를 선별하는 콜백으로, 전통적으로 표를 검사할 때의 조건에 따라 변환해야 한다.
// 이 조건은 where(['meet_id'=>9211, 'order_id'=>$datum['order_id'], 'status'=>['in', '0,1,2,3'])와 같습니다.
// 캐시된 데이터는 meet_id=9211의 집합이므로 이 조건은 기본적으로 사용되지 않습니다
$call=function ($item) use ($datum) {
if (in_array($item['status'),[0,1,2,3])&$item['order_id']==$datum['order_id']){
return $item
}
return null;
};
// 메모리 테이블을 호출하여 데이터를 직접 필터링합니다.
$d1=$table->whereCall($call)->order("id desc")->select();
//여기서 두 표의 선별 필드가 정확히 일치하면, 바로 위의 선별 조건을 사용하여 불일치 자신이 새로운 콜백을 만들면 된다.
$d2=$table2->whereCall($call)->order("id desc")->select();
}
//마지막 종료 시간
echo "finish_time_2=.microtime(true);
}
테스트 결과
반응형
'개발 꿀팁 > PHP' 카테고리의 다른 글
Pytho목록 (0) | 2022.11.17 |
---|---|
PHP에서의 오류 처리 약술 (0) | 2022.11.16 |
PHP RSA 및 RSA2 암호화 코드 (0) | 2022.11.09 |
php 읽기 ini 프로필 속성 (0) | 2022.11.09 |
php 작업 redis 예제 (0) | 2022.11.09 |