Merge pull request #2911 from int2001/sat_php_join

join sat-table in PHP instead of DB. Huge performance booster
This commit is contained in:
Joerg (DJ7NT)
2026-02-05 15:02:15 +01:00
committed by GitHub
4 changed files with 145 additions and 31 deletions

View File

@@ -2,8 +2,7 @@
class Dashboard extends CI_Controller {
public function index()
{
public function index() {
// Check if users logged in
$this->load->model('user_model');
if ($this->user_model->validate_session() == 0) {

View File

@@ -7,7 +7,6 @@ require_once APPPATH . '../src/Dxcc/Dxcc.php';
class Logbook extends CI_Controller {
function index() {
// Check if users logged in
$this->load->model('user_model');
if($this->user_model->validate_session() == 0) {
@@ -707,29 +706,66 @@ class Logbook extends CI_Controller {
$html = "";
if(!empty($logbooks_locations_array)) {
$this->db->select(''.$this->config->item('table_name').'.COL_CALL, '.$this->config->item('table_name').'.COL_BAND, '.$this->config->item('table_name').'.COL_FREQ, '.$this->config->item('table_name').'.COL_TIME_ON, '.$this->config->item('table_name').'.COL_RST_RCVD, '.$this->config->item('table_name').'.COL_RST_SENT, '.$this->config->item('table_name').'.COL_MODE, '.$this->config->item('table_name').'.COL_SUBMODE, '.$this->config->item('table_name').'.COL_PRIMARY_KEY, '.$this->config->item('table_name').'.COL_SAT_NAME, '.$this->config->item('table_name').'.COL_GRIDSQUARE, '.$this->config->item('table_name').'.COL_QSL_RCVD, '.$this->config->item('table_name').'.COL_EQSL_QSL_RCVD, '.$this->config->item('table_name').'.COL_EQSL_QSL_SENT, '.$this->config->item('table_name').'.COL_QSL_SENT, '.$this->config->item('table_name').'.COL_STX, '.$this->config->item('table_name').'.COL_STX_STRING, '.$this->config->item('table_name').'.COL_SRX, '.$this->config->item('table_name').'.COL_SRX_STRING, '.$this->config->item('table_name').'.COL_LOTW_QSL_SENT, '.$this->config->item('table_name').'.COL_LOTW_QSL_RCVD, '.$this->config->item('table_name').'.COL_VUCC_GRIDS, '.$this->config->item('table_name').'.COL_MY_GRIDSQUARE, '.$this->config->item('table_name').'.COL_CONTEST_ID, '.$this->config->item('table_name').'.COL_STATE, '.$this->config->item('table_name').'.COL_QRZCOM_QSO_UPLOAD_STATUS, '.$this->config->item('table_name').'.COL_QRZCOM_QSO_DOWNLOAD_STATUS, '.$this->config->item('table_name').'.COL_CLUBLOG_QSO_UPLOAD_STATUS, '.$this->config->item('table_name').'.COL_CLUBLOG_QSO_DOWNLOAD_STATUS, '.$this->config->item('table_name').'.COL_POTA_REF, '.$this->config->item('table_name').'.COL_IOTA, '.$this->config->item('table_name').'.COL_SOTA_REF, '.$this->config->item('table_name').'.COL_WWFF_REF, '.$this->config->item('table_name').'.COL_OPERATOR, '.$this->config->item('table_name').'.COL_COUNTRY, station_profile.*, satellite.displayname AS sat_displayname');
$this->db->from($this->config->item('table_name'));
$this->db->join('station_profile', 'station_profile.station_id = '.$this->config->item('table_name').'.station_id');
$this->db->join('satellite', 'satellite.name = '.$this->config->item('table_name').'.COL_SAT_NAME', 'left outer');
$this->db->where_in('station_profile.station_id', $logbooks_locations_array);
$this->db->group_start();
$this->db->where($this->config->item('table_name').'.COL_CALL', $lookupcall);
$this->db->or_like($this->config->item('table_name').'.COL_CALL', '/'.$lookupcall,'before');
$this->db->or_like($this->config->item('table_name').'.COL_CALL', $lookupcall.'/','after');
$this->db->or_like($this->config->item('table_name').'.COL_CALL', '/'.$lookupcall.'/');
$this->db->group_end();
$this->db->order_by($this->config->item('table_name').".COL_TIME_ON", "desc");
$this->db->order_by($this->config->item('table_name').".COL_PRIMARY_KEY", "desc");
$this->db->limit($count);
$query = $this->db->get();
// Load all satellites once for PHP-side join (much faster than SQL join)
$satellites = [];
$sat_query = $this->db->query('SELECT name, displayname FROM satellite');
foreach ($sat_query->result() as $sat) {
$satellites[$sat->name] = $sat->displayname;
}
if (!empty($logbooks_locations_array) && $query->num_rows() > 0) {
if(!empty($logbooks_locations_array)) {
$station_ids = implode(',', array_map(function($id) { return (int)$id; }, $logbooks_locations_array));
$bindings = [
$lookupcall, // Exact match: COL_CALL = ?
'/' . $lookupcall, // Starts with /: COL_CALL LIKE '/ABC'
$lookupcall . '/', // Ends with /: COL_CALL LIKE 'ABC/'
'/' . $lookupcall . '/', // Both sides: COL_CALL LIKE '/ABC/'
(int)$count // LIMIT
];
$sql = "SELECT
qsos.COL_CALL, qsos.COL_BAND, qsos.COL_FREQ, qsos.COL_TIME_ON,
qsos.COL_RST_RCVD, qsos.COL_RST_SENT, qsos.COL_MODE, qsos.COL_SUBMODE,
qsos.COL_PRIMARY_KEY, qsos.COL_SAT_NAME, qsos.COL_GRIDSQUARE,
qsos.COL_QSL_RCVD, qsos.COL_EQSL_QSL_RCVD, qsos.COL_EQSL_QSL_SENT,
qsos.COL_QSL_SENT, qsos.COL_STX, qsos.COL_STX_STRING, qsos.COL_SRX,
qsos.COL_SRX_STRING, qsos.COL_LOTW_QSL_SENT, qsos.COL_LOTW_QSL_RCVD,
qsos.COL_VUCC_GRIDS, qsos.COL_MY_GRIDSQUARE, qsos.COL_CONTEST_ID,
qsos.COL_STATE, qsos.COL_QRZCOM_QSO_UPLOAD_STATUS,
qsos.COL_QRZCOM_QSO_DOWNLOAD_STATUS, qsos.COL_CLUBLOG_QSO_UPLOAD_STATUS,
qsos.COL_CLUBLOG_QSO_DOWNLOAD_STATUS, qsos.COL_POTA_REF, qsos.COL_IOTA,
qsos.COL_SOTA_REF, qsos.COL_WWFF_REF, qsos.COL_OPERATOR, qsos.COL_COUNTRY,
station_profile.*
FROM " . $this->config->item('table_name') . " qsos
JOIN station_profile ON station_profile.station_id = qsos.station_id
WHERE station_profile.station_id IN ($station_ids)
AND (
qsos.COL_CALL = ?
OR qsos.COL_CALL LIKE ?
OR qsos.COL_CALL LIKE ?
OR qsos.COL_CALL LIKE ?
)
ORDER BY qsos.COL_TIME_ON DESC, qsos.COL_PRIMARY_KEY DESC
LIMIT ?";
$query = $this->db->query($sql, $bindings);
// Add satellite data via PHP-side join
$results = $query->result();
foreach ($results as &$row) {
$row->sat_name = $row->COL_SAT_NAME ?? null;
$row->sat_displayname = null;
if (!empty($row->COL_SAT_NAME) && isset($satellites[$row->COL_SAT_NAME])) {
$row->sat_displayname = $satellites[$row->COL_SAT_NAME];
}
}
unset($row);
} else {
$results = [];
}
if (!empty($results)) {
$html .= "<div class=\"table-responsive\">";
$html .= "<table class=\"table table-striped\">";
$html .= "<tr>";
@@ -771,7 +807,7 @@ class Logbook extends CI_Controller {
$custom_date_format = $this->config->item('qso_date_format');
}
foreach ($query->result() as $row) {
foreach ($results as $row) {
$timestamp = strtotime($row->COL_TIME_ON ?? '1970-01-01 00:00:00');
$html .= "<tr>";
$html .= "<td>".date($custom_date_format, $timestamp). date(' H:i',strtotime($row->COL_TIME_ON ?? '1970-01-01 00:00:00')) . "</td>";

View File

@@ -2163,13 +2163,19 @@ class Logbook_model extends CI_Model {
return array();
}
// Load all satellites once for PHP-side join (much faster than SQL COALESCE)
$satellites = [];
$sat_query = $this->db->select('name, displayname')->get('satellite');
foreach ($sat_query->result() as $sat) {
$satellites[$sat->name] = $sat->displayname;
}
$binding = array();
$sql = "SELECT qsos.*, station_profile.*, dxcc_entities.*, lotw_users.callsign, lotw_users.lastupload, satellite.displayname AS sat_displayname, satellite.name AS sat_name
$sql = "SELECT qsos.*, station_profile.*, dxcc_entities.*, lotw_users.callsign, lotw_users.lastupload
FROM ".$this->config->item('table_name')." qsos
JOIN `station_profile` ON `station_profile`.`station_id` = qsos.`station_id`
LEFT JOIN `dxcc_entities` ON qsos.`col_dxcc` = `dxcc_entities`.`adif`
LEFT OUTER JOIN `lotw_users` ON `lotw_users`.`callsign` = qsos.`col_call`
LEFT OUTER JOIN satellite ON qsos.col_prop_mode='SAT' and qsos.COL_SAT_NAME = COALESCE(NULLIF(satellite.name, ''), NULLIF(satellite.displayname, ''))
WHERE 1=1";
if ($band != '') {
if ($band == 'SAT') {
@@ -2194,7 +2200,39 @@ class Logbook_model extends CI_Model {
$binding[] = (int) $offset;
}
$sql .= ";";
return $this->db->query($sql, $binding);
$query = $this->db->query($sql, $binding);
// Add satellite data via PHP-side join (much faster than SQL COALESCE join)
$results = $query->result();
foreach ($results as &$row) {
$row->sat_name = $row->COL_SAT_NAME ?? null;
$row->sat_displayname = null;
if (!empty($row->COL_SAT_NAME) && isset($satellites[$row->COL_SAT_NAME])) {
$row->sat_displayname = $satellites[$row->COL_SAT_NAME];
}
}
unset($row);
// Return a query-like object with result() method for compatibility
return new class($results) {
private $data;
public function __construct($data) {
$this->data = $data;
}
public function result() {
return $this->data;
}
public function num_rows() {
return count($this->data);
}
public function num_fields() {
return empty($this->data) ? 0 : count(get_object_vars($this->data[0]));
}
};
}
function get_qso($id, $trusted = false) {

View File

@@ -94,6 +94,13 @@ class Logbookadvanced_model extends CI_Model {
}
public function searchDb($searchCriteria) {
// Load all satellites once for PHP-side join (much faster than SQL COALESCE)
$satellites = [];
$sat_query = $this->db->query('SELECT name, displayname FROM satellite');
foreach ($sat_query->result() as $sat) {
$satellites[$sat->name] = $sat->displayname;
}
$conditions = [];
$binding = [$searchCriteria['user_id']];
@@ -637,10 +644,9 @@ class Logbookadvanced_model extends CI_Model {
}
$sql = "
SELECT qsos.*, qsos.last_modified AS qso_last_modified, dxcc_entities.*, lotw_users.*, station_profile.*, satellite.*, dxcc_entities.name as dxccname, mydxcc.name AS station_country, exists(select 1 from qsl_images where qsoid = qsos.COL_PRIMARY_KEY) as qslcount, coalesce(contest.name, qsos.col_contest_id) as contestname
SELECT qsos.*, qsos.last_modified AS qso_last_modified, dxcc_entities.*, lotw_users.*, station_profile.*, dxcc_entities.name as dxccname, mydxcc.name AS station_country, exists(select 1 from qsl_images where qsoid = qsos.COL_PRIMARY_KEY) as qslcount, coalesce(contest.name, qsos.col_contest_id) as contestname
FROM " . $this->config->item('table_name') . " qsos
INNER JOIN station_profile ON qsos.station_id=station_profile.station_id
LEFT OUTER JOIN satellite ON qsos.col_prop_mode='SAT' and qsos.COL_SAT_NAME = COALESCE(NULLIF(satellite.name, ''), NULLIF(satellite.displayname, ''))
LEFT OUTER JOIN dxcc_entities ON qsos.col_dxcc = dxcc_entities.adif
left outer join dxcc_entities mydxcc on qsos.col_my_dxcc = mydxcc.adif
LEFT OUTER JOIN lotw_users ON qsos.col_call = lotw_users.callsign
@@ -651,7 +657,42 @@ class Logbookadvanced_model extends CI_Model {
$sortorder
$limit
";
return $this->db->query($sql, $binding);
$query = $this->db->query($sql, $binding);
// Add satellite data via PHP-side join (much faster than SQL COALESCE)
$results = $query->result();
foreach ($results as &$row) {
$row->sat_name = $row->COL_SAT_NAME ?? null;
$row->sat_displayname = null;
if (!empty($row->COL_SAT_NAME) && isset($satellites[$row->COL_SAT_NAME])) {
$row->sat_displayname = $satellites[$row->COL_SAT_NAME];
}
}
unset($row);
// Return a query-like object with result() method for compatibility
return new class($results) {
private $data;
public function __construct($data) {
$this->data = $data;
}
public function result($type = 'object') {
if ($type === 'array') {
return json_decode(json_encode($this->data), true);
}
return $this->data;
}
public function num_rows() {
return count($this->data);
}
public function row() {
return !empty($this->data) ? $this->data[0] : null;
}
};
}