redis hash構造はあるkeyの下のすべての(field,values)の方法を遍歴する.
4791 ワード
本文は同時にhttps://github.com/zhangyachen/zhangyachen.github.io/issues/95
redisのhash構造には、次のようなデータが格納されています.
需要:毎日未明にタイミングスクリプトを走って、1つのkeyの下のすべてのqidを飛び出して、現在の時間とvalueを判断して、redis経由 DBにkey=>qidのセットを格納する. redis経由
redisのHGETALLコマンドで
result:
しかし、この方法には2つの欠点があります.会社のredis中間層が返却データに64 KBサイズの制限をしており、返却パケットのサイズが64 KBを超えるとエラーが返される. HGETALLはビッグデータセットでは非効率であり、複雑度はO(n)、nはhashテーブルの大きさである.
廃棄する.
DBにkey=>qidのセットを格納
簡単に言えば、DBにもkey=>qidのマッピングが格納される.まずkeyに対応するqidがどれらがあるかを検索し、redisで検索するには、必要な操作はHGET操作だけです.
この方法の欠点は,DBからqidを取り出すには,qid集合をループしてredisを何度も読み返す必要があり,HGETALLのように一度に全部読めるものではないということである.しかし、ループループ操作は、次の2つの方法で解決できると思います.ループスルー操作を一括読み出しに変更: データベースにstartTimeとendTimeの2つのフィールドを追加し、どのqidが期限切れであるかをデータベース層で直接判断し、期限切れのqidを取り出し、直接データに組み立て、呼び出す
期限切れのqidが翌日に繰り返されるのを防止するため、期限切れのqidセットが発見された場合、対応するdeletedフィールドを2に設定します.これにより繰り返し読み取りが防止され(
採用する.
redisの
HSCANコマンドについて:SCAN
基本思想は、redis自身のHGETALLよりも、1つのキーの下にある全ての(field,value)を読み取ることができる.しかし、ループ読み出しであるため、redisサーバのリソースと時間の消費は少ない. DBにkey=>qidのマッピングを冗長に格納する必要がなく、操作も比較的簡単である.
しかし、悲しいことに、会社のredisサービス層はhscanコマンドをサポートしていません.
あきらめる.
以上、第2の方法として、DBにkey=>qidのセットを格納する.
転載先:https://www.cnblogs.com/zhangyachen/p/8033279.html
redisのhash構造には、次のようなデータが格納されています.
$input = array(
"key" => $key, // key
"qid" => $qid, // id
"value" => $startTime_$endTime, // _
)
需要:毎日未明にタイミングスクリプトを走って、1つのkeyの下のすべてのqidを飛び出して、現在の時間とvalueを判断して、
$endTime
どうやってすべての(field,values)を見つけたのでしょうか?HGETALL
コマンド.HSCAN
コマンド.redisのHGETALLコマンドで
$input = array(
"key" => $key,
);
$ret = $objRedis->HGETALL($input);
var_dump($ret);
result:
array(3) {
["ret"]=>
array(1) {
["business_AdvancedPackageOne_2"]=>
array(16) {
[0]=>
array(2) {
["field"]=>
string(2) "58"
["value"]=>
string(3) "1_1"
}
[1]=>
array(2) {
["field"]=>
string(2) "56"
["value"]=>
string(5) "56_57"
}
[2]=>
array(2) {
["field"]=>
string(2) "57"
["value"]=>
string(5) "57_58"
}
...
}
}
["err_no"]=>
int(0)
["err_msg"]=>
string(2) "OK"
}
しかし、この方法には2つの欠点があります.
廃棄する.
DBにkey=>qidのセットを格納
簡単に言えば、DBにもkey=>qidのマッピングが格納される.まずkeyに対応するqidがどれらがあるかを検索し、redisで検索するには、必要な操作はHGET操作だけです.
$input = array(
"key" => $key, // key
"qid" => $qid, // id
)
$ret = $objRedis->HGET($input);
この方法の欠点は,DBからqidを取り出すには,qid集合をループしてredisを何度も読み返す必要があり,HGETALLのように一度に全部読めるものではないということである.しかし、ループループ操作は、次の2つの方法で解決できると思います.
$input = array(
'reqs' => array(
$input1,
$input2,
...,
),
);
$rpc->$cmd($input);
hdel
一括してすべて削除(以下、私のスクリプトのコードの一部):/**
* @desc 1 qid
* @param $objBusinessDB
* @param $businessId
* @param $currentTime
* @return array
*/
function getMergeQid($objBusinessDB,$businessId,$currentTime){
// qid
$outDateQid = array();
$outDateId = array();
//
$sql = "select * from busines_package where businessId={$businessId} and endTimequery($sql);
if($dbRet === false){
Bd_Log::warning("select table fail.sql[".$sql."]");
return $outDateQid;
}
foreach($dbRet as $value){
$extpack = mc_pack_pack2array($value['extpack']);
// qid
if(isset($extpack['qid']) && !empty($extpack['qid'])){
$outDateQid = array_merge($outDateQid,$extpack['qid']);
}
$outDateId[] = intval($value['id']);
}
$sql = sprintf("update business_package set deleted=2 where id in (%s)",implode($outDateId));
$dbRet = $objBusinessDB->query($sql);
if($dbRet === false){
Bd_Log::warning("update table fail.sql[".$sql."]");
}
return $outDateQid;
}
// qid
$outDateQid = getMergeQid($objBusinessDB,$businessId,$currentTime);
// redis qid
$redisRet = $objDaoRedis->HDEL($redisKey,$outDateQid);
if($redisRet['err_no'] != 0){
Bd_Log::warning("delete advancedPackage fail.businessId[$businessId] currentTime[$currentTime]");
}
期限切れのqidが翌日に繰り返されるのを防止するため、期限切れのqidセットが発見された場合、対応するdeletedフィールドを2に設定します.これにより繰り返し読み取りが防止され(
where deleted=0
)、効率が向上します.採用する.
redisの
HSCAN
コマンドでHSCANコマンドについて:SCAN
基本思想は、redis自身の
HSCAN
コマンドにより、1つのkeyの下のすべてのqidをループ読み出します.利点は明らかです.しかし、悲しいことに、会社のredisサービス層はhscanコマンドをサポートしていません.
array(2) {
["err_no"]=>
int(405)
["err_msg"]=>
string(37) "Unknown Method: unknown method(HSCAN)"
}
あきらめる.
以上、第2の方法として、DBにkey=>qidのセットを格納する.
転載先:https://www.cnblogs.com/zhangyachen/p/8033279.html