架構師之路——沈劍:炸!業界難題,跨庫分頁的幾種常見方案
當兩表數據相對均衡的情況下比較適用
<?php
function getPage($a, $b, $page, $page_size){
sort($a);
sort($b);
$total_a = count($a);
$total_b = count($b);
$averge = floor($page*$page_size/2);
$a_f = array_slice($a, $averge, $page_size); # 升序序列 first
$b_f = array_slice($b, $averge, $page_size); # 升序序列
$a_f_len = count($a_f);
$b_f_len = count($b_f);
$min_a = $a_f[0] ?? null;
$min_b = $b_f[0] ?? null;
$max_a = $a_f[$a_f_len-1] ?? null;
$max_b = $b_f[$b_f_len-1] ?? null;
if (empty($a_f)) {
$min = $min_b;
$a_s = getRangeInfo($a, $min_b, $max_a);
$offset = count($a_s)+ ($averge-$total_a);
}
if (empty($b_f)) {
$min = $min_a;
$b_s = getRangeInfo($a, $min_a, $max_b);
$offset = count($b_s)+ ($averge-$total_b);
}
if (!empty($a_f) && !empty($b_f)) {
$min = min([$min_a, $min_b]);
if($min_a > $min_b || empty($b_f)) # b組數據小 重新查詢a組
{
# 查出偏移量
# 第二次查詢 second
$a_s = getRangeInfo($a, $min, $max_a); # second 第二次查找
# 求出新查出的數據與最開始查出a數組相差個數
$offset = count($a_s)-$a_f_len;
} else { # a組數據小 重新查詢b組
# 查出偏移量
$b_s = getRangeInfo($b, $min, $max_b);
# 求出新查出的數據與最開始查出a數組相差個數
$offset = count($b_s)-$b_f_len;
}
}
$now_position = $show = (int)($averge*2-$offset);
$start_position = $page*$page_size;
$end_position = ($page+1)*$page_size-1;
// 假如一次查詢某數組爲空,查詢的第二組數據未能涵蓋所需全部數據,故重新查詢
$a_s = getlimit($a, $min, $start_position-$now_position+$page_size);
$b_s = getlimit($b, $min, $start_position-$now_position+$page_size);
$total_arr = array_merge($a_s, $b_s) ;
sort( $total_arr); # 升序排列
$res = [];
foreach ($total_arr as $k=>$v) {
if ($now_position > $end_position) {
break;
}
if ($now_position < $start_position){
$now_position = $now_position+1;
continue;
}
$now_position = $now_position+1;
$res[] = $v;
}
// 思路如下:
$min_str = $min_a > $min_b ? ' 最小數在b, 重新獲取a數據'.json_encode($a_s):'最小數在a, 重新獲取b數據'.json_encode($b_s);
print_r('數組$a:'.json_encode($a));
echo '<br>';
print_r('數組$b:'.json_encode($b));
echo '<br>';
print_r('平均數floor is '.$averge.', $a 最小值是 '.$min_a.',$b 最小值是 '.$min_b.', 對比之後得出最小值是'.$min.','.$min_str.
'此時偏移量'.$offset.', 最小數'.$min.'處於位置'.$show.', 我需要'.$start_position.'到'.$end_position.'的數據,
查出所需數據爲'.json_encode($total_arr).', 結果爲'.json_encode($res));
return $res;
}
// 按值範圍獲取
function getRangeInfo ($array, $start_value, $end_value)
{
sort($array);
$res = [];
foreach ($array as $k => $v)
{
if ($v >= $start_value && $v <= $end_value){
$res[] = $v;
}
}
return $res;
}
// 按起始位置個數獲取
function getlimit ($array, $start_value, $num)
{
sort($array);
$res = [];
foreach ($array as $k => $v)
{
if ($num<=0) {
break;
}
if ($v >= $start_value){
$res[] = $v;
$num --;
}
}
return $res;
}
$b = [1];
$a = [2,3,1,4,5,6,7,8,9,10,12,14];
$page = 2; # 第一頁
$page_size = 5;
$list = getPage($a, $b, $page, $page_size);
$all = array_merge($a, $b);
sort($all);
echo '<br>';echo '<br>';
echo '<br>';
$start_position = $page*$page_size;
$real = array_slice($all, $start_position, $page_size);
print_r('合併總數據'.json_encode($all).',一頁'.$page_size.'條, 第'.(string)($page+1).'頁數據爲:'.json_encode($real));