NEW Can use the result_mode of mysqli driver. Save memory for list count

This commit is contained in:
Laurent Destailleur 2021-08-16 22:01:58 +02:00
parent d7317025e9
commit 06a0d922cc
7 changed files with 62 additions and 28 deletions

View File

@ -519,19 +519,40 @@ $sql .= $hookmanager->resPrint;
$sql .= $db->order($sortfield, $sortorder); $sql .= $db->order($sortfield, $sortorder);
$nbtotalofrecords = ''; $nbtotalofrecords = ''; // TODO We can set and use an optimized request in $sqlforcount with no fields and no useless join to calculate nb of records
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
// TODO Set and use an optimized request in $sqlforcount with no fields and no useless join to caluclate nb of records /* This old method to get and count full list returns all record so use a high amount of memory.
$result = $db->query($sql); $resql = $db->query($sql);
$nbtotalofrecords = $db->num_rows($result); $nbtotalofrecords = $db->num_rows($resql);
*/
/* The new method does not consume memory on mysql (not tested on pgsql) */
$resql = $db->query($sql, 0, 'auto', 1);
while ($db->fetch_object($resql)) {
$nbtotalofrecords++;
}
if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0 if (($page * $limit) > $nbtotalofrecords) { // if total resultset is smaller then paging size (filtering), goto and load page 0
$page = 0; $page = 0;
$offset = 0; $offset = 0;
} }
$db->free($resql);
} }
// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set.
if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) {
$num = $nbtotalofrecords;
} else {
if ($limit) {
$sql .= $db->plimit($limit + 1, $offset); $sql .= $db->plimit($limit + 1, $offset);
//print $sql; }
$resql = $db->query($sql);
if (!$resql) {
dol_print_error($db);
exit;
}
$num = $db->num_rows($resql);
}
dol_syslog("comm/action/list.php", LOG_DEBUG); dol_syslog("comm/action/list.php", LOG_DEBUG);
$resql = $db->query($sql); $resql = $db->query($sql);

View File

@ -218,9 +218,10 @@ interface Database
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions). * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode
* @return resource Resultset of answer * @return resource Resultset of answer
*/ */
public function query($query, $usesavepoint = 0, $type = 'auto'); public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0);
/** /**
* Connexion to server * Connexion to server

View File

@ -262,9 +262,10 @@ class DoliDBMysqli extends DoliDB
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions). * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode
* @return bool|mysqli_result Resultset of answer * @return bool|mysqli_result Resultset of answer
*/ */
public function query($query, $usesavepoint = 0, $type = 'auto') public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
{ {
global $conf, $dolibarr_main_db_readonly; global $conf, $dolibarr_main_db_readonly;
@ -289,9 +290,9 @@ class DoliDBMysqli extends DoliDB
if (!$this->database_name) { if (!$this->database_name) {
// Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE) // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
$ret = $this->db->query($query); $ret = $this->db->query($query, $result_mode);
} else { } else {
$ret = $this->db->query($query); $ret = $this->db->query($query, $result_mode);
} }
if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) { if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
@ -316,7 +317,7 @@ class DoliDBMysqli extends DoliDB
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/** /**
* Renvoie la ligne courante (comme un objet) pour le curseur resultset * Returns the current line (as an object) for the resultset cursor
* *
* @param mysqli_result $resultset Curseur de la requete voulue * @param mysqli_result $resultset Curseur de la requete voulue
* @return object|null Object result line or null if KO or end of cursor * @return object|null Object result line or null if KO or end of cursor

View File

@ -494,9 +494,10 @@ class DoliDBPgsql extends DoliDB
* @param string $query SQL query string * @param string $query SQL query string
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions). * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode (not used with pgsql)
* @return false|resource Resultset of answer * @return false|resource Resultset of answer
*/ */
public function query($query, $usesavepoint = 0, $type = 'auto') public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
{ {
global $conf, $dolibarr_main_db_readonly; global $conf, $dolibarr_main_db_readonly;
@ -570,7 +571,7 @@ class DoliDBPgsql extends DoliDB
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/** /**
* Renvoie la ligne courante (comme un objet) pour le curseur resultset * Returns the current line (as an object) for the resultset cursor
* *
* @param resource $resultset Curseur de la requete voulue * @param resource $resultset Curseur de la requete voulue
* @return false|object Object result line or false if KO or end of cursor * @return false|object Object result line or false if KO or end of cursor

View File

@ -393,9 +393,10 @@ class DoliDBSqlite3 extends DoliDB
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions). * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions).
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode (not used with sqlite)
* @return SQLite3Result Resultset of answer * @return SQLite3Result Resultset of answer
*/ */
public function query($query, $usesavepoint = 0, $type = 'auto') public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
{ {
global $conf, $dolibarr_main_db_readonly; global $conf, $dolibarr_main_db_readonly;
@ -504,7 +505,7 @@ class DoliDBSqlite3 extends DoliDB
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/** /**
* Renvoie la ligne courante (comme un objet) pour le curseur resultset * Returns the current line (as an object) for the resultset cursor
* *
* @param SQLite3Result $resultset Curseur de la requete voulue * @param SQLite3Result $resultset Curseur de la requete voulue
* @return false|object Object result line or false if KO or end of cursor * @return false|object Object result line or false if KO or end of cursor

View File

@ -292,13 +292,14 @@ class TraceableDB extends DoliDB
* @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions). * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions).
* Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints.
* @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...)
* @param int $result_mode Result mode
* @return resource Resultset of answer * @return resource Resultset of answer
*/ */
public function query($query, $usesavepoint = 0, $type = 'auto') public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
{ {
$this->startTracing(); $this->startTracing();
$resql = $this->db->query($query, $usesavepoint, $type); $resql = $this->db->query($query, $usesavepoint, $type, $result_mode);
$this->endTracing($query, $resql); $this->endTracing($query, $resql);

View File

@ -349,12 +349,20 @@ $sql .= $db->order($sortfield, $sortorder);
// Count total nb of records // Count total nb of records
$nbtotalofrecords = ''; $nbtotalofrecords = '';
if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) {
/* This old method to get and count full list returns all record so use a high amount of memory.
$resql = $db->query($sql); $resql = $db->query($sql);
$nbtotalofrecords = $db->num_rows($resql); $nbtotalofrecords = $db->num_rows($resql);
*/
/* The new method does not consume memory on mysql (not tested on pgsql) */
$resql = $db->query($sql, 0, 'auto', 1);
while ($db->fetch_object($resql)) {
$nbtotalofrecords++;
}
if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0 if (($page * $limit) > $nbtotalofrecords) { // if total of record found is smaller than page * limit, goto and load page 0
$page = 0; $page = 0;
$offset = 0; $offset = 0;
} }
$db->free($resql);
} }
// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set. // if total of record found is smaller than limit, no need to do paging and to restart another select with limits set.
if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) { if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit))) {