changeset 7165:6d0f6a686b71 default tip

moved the DB specific criteria to run ANALYZE out of the OrthancFramework
author Alain Mazy <am@orthanc.team>
date Wed, 30 Sep 2026 14:58:05 +0200
parents 22083f3fe932
children
files OrthancFramework/Sources/SQLite/Connection.cpp OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h
diffstat 3 files changed, 32 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/SQLite/Connection.cpp	Wed Sep 30 14:17:23 2026 +0200
+++ b/OrthancFramework/Sources/SQLite/Connection.cpp	Wed Sep 30 14:58:05 2026 +0200
@@ -232,20 +232,15 @@
       return false;
     }
 
-    void Connection::Optimize(bool onlyIfStatsDontExists)
+    void Connection::Optimize(bool onlyIfStatsDontExistsYet)
     {
-      if (onlyIfStatsDontExists)
+      if (onlyIfStatsDontExistsYet)
       {
         if (!DoesTableExist("sqlite_stat1")) // create the table if it does not exist yet and if there are enough data in the Resources table
         {
-          Statement countResources(*this, std::string("SELECT COUNT(*) FROM Resources WHERE resourceType=") + boost::lexical_cast<std::string>(ResourceType_Study));    
-          countResources.Step();
-          if (countResources.ColumnInt64(0) > 50)  // no need to ANALYZE if there are not enough data in the table (wait for 50 studies)
-          {
-            CLOG(WARNING, SQLITE) << "SQLite: Performing first ANALYZE to improve the query planner";
-            Statement analyze(*this, "ANALYZE");
-            analyze.Run();
-          }
+          CLOG(WARNING, SQLITE) << "SQLite: Performing first ANALYZE to improve the query planner";
+          Statement analyze(*this, "ANALYZE");
+          analyze.Run();
         }
       }
       else
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Sep 30 14:17:23 2026 +0200
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Sep 30 14:58:05 2026 +0200
@@ -2884,8 +2884,8 @@
           ExecuteEmbeddedScript(db_, ServerResources::ADD_TIMEOUT_TO_QUEUES);
         }
 
-        // New in Orthanc 1.13.1 run optimize at each startup
-        db_.Optimize(false);
+        // New in Orthanc 1.13.1 run optimize at each startup, provided there are enough data to perform a relevant analysis
+        Optimize(false);
       }
 
       transaction->Commit(0);
@@ -3020,12 +3020,32 @@
   }
 
 
+  bool SQLiteDatabaseWrapper::Optimize(bool onlyIfStatsDontExistsYet)
+  {
+    SQLite::Statement countResources(db_, std::string("SELECT COUNT(*) FROM Resources WHERE resourceType=") + boost::lexical_cast<std::string>(ResourceType_Study));    
+    countResources.Step();
+    
+    if (countResources.ColumnInt64(0) > 50)  // no need to ANALYZE if there are not enough data in the table (wait for 50 studies)
+    {
+      db_.Optimize(onlyIfStatsDontExistsYet);
+      return true;
+    }
+
+    return false;
+  }
+
+
   void SQLiteDatabaseWrapper::FlushToDisk()
   {
     boost::recursive_mutex::scoped_lock lock(mutex_);
-
-    // this will run ANALYZE only once whe the Resources table contains enough rows
-    db_.Optimize(true);
+    static bool hasRunOptimizeOnce = false;
+
+    if (!hasRunOptimizeOnce)
+    {
+      // This will run ANALYZE only once whe the Resources table contains reaches a predefined size and if there are no index statistics yet.
+      // Then, an OPTIMIZE step will run at each startup (and will execute ANALYZE if it makes sense)
+      hasRunOptimizeOnce = Optimize(true /* onlyIfStatsDontExistsYet */);
+    }
 
     db_.FlushToDisk();
   }
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h	Wed Sep 30 14:17:23 2026 +0200
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h	Wed Sep 30 14:58:05 2026 +0200
@@ -65,6 +65,8 @@
                                       SQLite::Statement& s,
                                       uint32_t maxResults);
 
+    bool Optimize(bool onlyIfStatsDontExistsYet);
+
   public:
     SQLiteDatabaseWrapper(const std::string& path);