More statistics on various objects, databases, indexes, and functions (8.4+
authorguillaume <guillaume@a7884b65-44f6-0310-8a51-81a127f17b15>
Fri, 24 Jul 2009 11:54:05 +0000 (11:54 +0000)
committerguillaume <guillaume@a7884b65-44f6-0310-8a51-81a127f17b15>
Fri, 24 Jul 2009 11:54:05 +0000 (11:54 +0000)
only for the last one).

git-svn-id: svn://svn.pgadmin.org/trunk/pgadmin3@7981 a7884b65-44f6-0310-8a51-81a127f17b15

CHANGELOG
pgadmin/include/schema/pgDatabase.h
pgadmin/include/schema/pgFunction.h
pgadmin/include/schema/pgIndex.h
pgadmin/schema/pgDatabase.cpp
pgadmin/schema/pgFunction.cpp
pgadmin/schema/pgIndex.cpp

index 1065031a5ab664c32084209177201a351601b6ca..86735ee04bfcc2ff3bb1f939d32cd27f3c797af1 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -36,8 +36,10 @@ Changes
 \r
 Date       Dev Ver     Change details\r
 ---------- --- ------  --------------\r
+2009-07-24 GL  1.12.0  More statistics on various objects, databases, indexes,\r
+                       and functions (8.4+ only for the last one).\r
 2009-07-24 GL  1.10.1  Fix the menu entry in frmQuery, per a report from Luiz\r
-                       K. Matsumura\r
+                       K. Matsumura.\r
 2009-07-21 DP  1.12.0  Add the partition name to the properties pane when viewing\r
                        the partitions of a table on GreenPlum [Chuck McDevitt].\r
 2009-07-20 GL  1.10.1  Fix the dlgFunction handling of preload libraries, per\r
index 1cd0a29d8f06d5487a934f9b3e92a962f5c32338..1bfaf0d16ac597ca1ff9aad9b4622bde7d750f7d 100644 (file)
@@ -44,6 +44,7 @@ public:
 
     void ShowTreeDetail(ctlTree *browser, frmMain *form=0, ctlListView *properties=0, ctlSQLBox *sqlPane=0);
     void ShowHint(frmMain *form, bool force);
+    void ShowStatistics(frmMain *form, ctlListView *statistics);
 
     pgSet *ExecuteSet(const wxString& sql);
     wxString ExecuteScalar(const wxString& sql);
index 0ec5e96bcd1d306b03860b2552277731f9c5b162..c1d2dfd36dd3228552a7553f788d98079af31bd3 100644 (file)
@@ -14,7 +14,6 @@
 
 #include "pgSchema.h"
 
-class pgCollection;
 class pgFunction;
 
 class pgFunctionFactory : public pgSchemaObjFactory
@@ -23,6 +22,7 @@ public:
     pgFunctionFactory(const wxChar *tn=0, const wxChar *ns=0, const wxChar *nls=0, const char **img=0);
     virtual dlgProperty *CreateDialog(frmMain *frame, pgObject *node, pgObject *parent);
     virtual pgObject *CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr=wxEmptyString);
+    virtual pgCollection *CreateCollection(pgObject *obj);
 
     pgFunction *AppendFunctions(pgObject *obj, pgSchema *schema, ctlTree *browser, const wxString &restriction);
 };
@@ -39,6 +39,7 @@ public:
 
     void ShowTreeDetail(ctlTree *browser, frmMain *form=0, ctlListView *properties=0, ctlSQLBox *sqlPane=0);
     bool CanDropCascaded() { return GetSchema()->GetMetaType() != PGM_CATALOG; }
+    void ShowStatistics(frmMain *form, ctlListView *statistics);
 
     virtual bool GetIsProcedure() const {return false; }
 
@@ -112,6 +113,14 @@ private:
 };
 
 
+class pgFunctionCollection : public pgSchemaObjCollection
+{
+public:
+    pgFunctionCollection(pgaFactory *factory, pgSchema *sch);
+    void ShowStatistics(frmMain *form, ctlListView *statistics);
+};
+
+
 class pgTriggerFunctionFactory : public pgFunctionFactory
 {
 public:
index 65a1ac0cce7c4a3901f5549761dc8ba552788f15..42b38c00dc13c6902f35cb17614fd4f08370653f 100644 (file)
@@ -15,7 +15,6 @@
 #include "pgTable.h"
 #include <wx/arrstr.h>
 
-class pgCollection;
 
 
 
@@ -117,6 +116,7 @@ class pgIndexBaseFactory : public pgTableObjFactory
 {
 public:
     virtual pgObject *CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr=wxEmptyString);
+    virtual pgCollection *CreateCollection(pgObject *obj);
 protected:
     pgIndexBaseFactory(const wxChar *tn, const wxChar *ns, const wxChar *nls, const char **img) : pgTableObjFactory(tn, ns, nls, img) {}
 };
@@ -130,6 +130,14 @@ public:
 };
 extern pgIndexFactory indexFactory;
 
+class pgIndexBaseCollection : public pgTableObjCollection
+{
+public:
+    pgIndexBaseCollection(pgaFactory *factory, pgTable *tbl);
+    void ShowStatistics(frmMain *form, ctlListView *statistics);
+};
+
+
 class executePgstatindexFactory : public contextActionFactory
 {
 public:
index a53ad6cbd2c5e3b52185672be5695d5c36c2aaba..52bec39cfcc91f3d05c375aeafd30afe73179719 100644 (file)
@@ -180,6 +180,48 @@ void pgDatabase::ShowHint(frmMain *form, bool force)
 }
 
 
+void pgDatabase::ShowStatistics(frmMain *form, ctlListView *statistics)
+{
+    bool hasSize=GetConnection()->HasFeature(FEATURE_SIZE);
+
+    wxString sql=wxT("SELECT numbackends AS ") + qtIdent(_("Backends")) +
+             wxT(", xact_commit AS ") + qtIdent(_("Xact Committed")) +
+             wxT(", xact_rollback AS ") + qtIdent(_("Xact Rolled Back")) +
+             wxT(", blks_read AS ") + qtIdent(_("Blocks Read")) +
+             wxT(", blks_hit AS ") + qtIdent(_("Blocks Hit"));
+
+       if (GetConnection()->BackendMinimumVersion(8,3))
+               sql += wxT(", tup_returned AS ") + qtIdent(_("Tuples Returned")) +
+             wxT(", tup_fetched AS ") + qtIdent(_("Tuples Fetched")) +
+             wxT(", tup_inserted AS ") + qtIdent(_("Tuples Inserted")) +
+             wxT(", tup_updated AS ") + qtIdent(_("Tuples Updated")) +
+             wxT(", tup_deleted AS ") + qtIdent(_("Tuples Deleted"));
+
+    if (hasSize)
+        sql += wxT(", pg_size_pretty(pg_database_size(datid)) AS ") + qtIdent(_("Size"));
+
+    sql += wxT("\n  FROM pg_stat_database db WHERE datname=") + qtDbString(GetName());
+
+       // DisplayStatistics is not available for this object
+
+       CreateListColumns(statistics, _("Statistic"), _("Value"));
+
+       pgSet *stats = connection()->ExecuteSet(sql);
+
+       if (stats)
+       {
+               int col;
+               for (col=0 ; col < stats->NumCols() ; col++)
+               {
+                       if (!stats->ColName(col).IsEmpty())
+                               statistics->AppendItem(stats->ColName(col), stats->GetVal(col));
+               }
+               delete stats;
+       }
+
+}
+
+
 pgSet *pgDatabase::ExecuteSet(const wxString& sql)
 {
     pgSet *set=0;
index cb3bb805a1871d8d173c0484b9b34917074d7ab4..e285341b1e92bc67001d153fb406cd7c167c200c 100644 (file)
@@ -42,6 +42,20 @@ pgProcedure::pgProcedure(pgSchema *newSchema, const wxString& newName)
 {
 }
 
+void pgFunction::ShowStatistics(frmMain *form, ctlListView *statistics)
+{
+    if (GetConnection()->BackendMinimumVersion(8, 4))
+    {
+               wxString sql=wxT("SELECT calls AS ") + qtIdent(_("Number of calls")) +
+             wxT(", total_time AS ") + qtIdent(_("Total Time")) +
+             wxT(", self_time AS ") + qtIdent(_("Self Time")) +
+          wxT(" FROM pg_stat_user_functions") +
+          wxT(" WHERE schemaname = ") + qtDbString(GetSchema()->GetName()) +
+                 wxT(" AND funcname = ") + qtDbString(GetName());
+               DisplayStatistics(statistics, sql);
+       }
+}
+
 bool pgFunction::IsUpToDate()
 {
     wxString sql = wxT("SELECT xmin FROM pg_proc WHERE oid = ") + this->GetOidStr();
@@ -681,6 +695,11 @@ pgObject *pgFunctionFactory::CreateObjects(pgCollection *collection, ctlTree *br
 }
 
 
+pgCollection *pgFunctionFactory::CreateCollection(pgObject *obj)
+{
+    return new pgFunctionCollection(GetCollectionFactory(), (pgSchema*)obj);
+}
+
 pgObject *pgTriggerFunctionFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restr)
 {
     wxString funcRestriction=wxT(
@@ -738,3 +757,46 @@ pgProcedureFactory::pgProcedureFactory()
 
 pgProcedureFactory procedureFactory;
 static pgaCollectionFactory cfp(&procedureFactory, __("Procedures"), procedures_xpm);
+
+pgFunctionCollection::pgFunctionCollection(pgaFactory *factory, pgSchema *sch)
+: pgSchemaObjCollection(factory, sch)
+{
+}
+
+
+void pgFunctionCollection::ShowStatistics(frmMain *form, ctlListView *statistics)
+{
+    if (GetConnection()->BackendMinimumVersion(8, 4))
+    {
+               wxLogInfo(wxT("Displaying statistics for functions on ") + GetSchema()->GetName());
+
+               wxString sql=wxT("SELECT funcname, calls, total_time, self_time")
+                 wxT(" FROM pg_stat_user_functions")
+                 wxT(" WHERE schemaname = ") + qtDbString(GetSchema()->GetName())
+                 + wxT(" ORDER BY funcname");
+
+               // Add the statistics view columns
+               statistics->ClearAll();
+               statistics->AddColumn(_("Function"), 60);
+               statistics->AddColumn(_("Calls"), 50);
+               statistics->AddColumn(_("Total Time"), 60);
+               statistics->AddColumn(_("Self Time"), 60);
+
+               pgSet *stats = GetDatabase()->ExecuteSet(sql);
+               if (stats)
+               {
+                       long pos=0;
+                       while (!stats->Eof())
+                       {
+                               statistics->InsertItem(pos, stats->GetVal(wxT("funcname")), PGICON_STATISTICS);
+                               statistics->SetItem(pos, 1, stats->GetVal(wxT("calls")));
+                               statistics->SetItem(pos, 2, stats->GetVal(wxT("total_time")));
+                               statistics->SetItem(pos, 3, stats->GetVal(wxT("self_time")));
+                               stats->MoveNext();
+                               pos++;
+                       }
+
+                       delete stats;
+               }
+    }
+}
index 83d34b222894d272fec54a7e1edfeea531c5ee39..948c4e28517149f3f92a38c096e5835454fde05f 100644 (file)
@@ -491,6 +491,13 @@ pgObject *pgIndexBaseFactory::CreateObjects(pgCollection *coll, ctlTree *browser
 }
 
 
+pgCollection *pgIndexBaseFactory::CreateCollection(pgObject *obj)
+{
+    return new pgIndexBaseCollection(GetCollectionFactory(), (pgTable*)obj);
+}
+
+
+
 pgObject *pgIndexFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
 {
     return pgIndexBaseFactory::CreateObjects(collection, browser, restriction + wxT("\n   AND conname IS NULL"));
@@ -511,3 +518,62 @@ pgIndexFactory::pgIndexFactory()
 
 pgIndexFactory indexFactory;
 static pgaCollectionFactory cf(&indexFactory, __("Indexes"), indexes_xpm);
+
+
+pgIndexBaseCollection::pgIndexBaseCollection(pgaFactory *factory, pgTable *tbl)
+: pgTableObjCollection(factory, tbl)
+{
+}
+
+
+void pgIndexBaseCollection::ShowStatistics(frmMain *form, ctlListView *statistics)
+{
+    wxLogInfo(wxT("Displaying statistics for indexes on ") + GetTable()->GetName());
+
+    bool hasSize=GetConnection()->HasFeature(FEATURE_SIZE);
+
+    // Add the statistics view columns
+    statistics->ClearAll();
+    statistics->AddColumn(_("Index Name"));
+    statistics->AddColumn(_("Index Scans"));
+    statistics->AddColumn(_("Index Tuples Read"));
+    statistics->AddColumn(_("Index Tuples Fetched"));
+    if (hasSize)
+        statistics->AddColumn(_("Size"));
+
+    wxString sql = wxT("SELECT indexrelname, ")
+               wxT("idx_scan, idx_tup_read, idx_tup_fetch");
+
+    if (hasSize)
+        sql += wxT(", pg_size_pretty(pg_relation_size(") + GetOidStr() + wxT(")) AS ") + qtIdent(_("size"));
+
+    sql += wxT("\n")
+        wxT("  FROM pg_stat_all_indexes stat\n")
+        wxT("  JOIN pg_class cls ON cls.oid=indexrelid\n")
+        wxT("  LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0')\n")
+        wxT("  LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)\n")
+        wxT("  WHERE schemaname = ") + qtDbString(GetTable()->GetSchema()->GetName())
+               + wxT(" AND stat.relname = ") + qtDbString(GetTable()->GetName())
+               + wxT(" AND con.contype IS NULL")
+        + wxT("\n ORDER BY indexrelname");
+
+    pgSet *stats = GetDatabase()->ExecuteSet(sql);
+
+    if (stats)
+    {
+        long pos=0;
+        while (!stats->Eof())
+        {
+            statistics->InsertItem(pos, stats->GetVal(wxT("indexrelname")), PGICON_STATISTICS);
+            statistics->SetItem(pos, 1, stats->GetVal(wxT("idx_scan")));
+            statistics->SetItem(pos, 2, stats->GetVal(wxT("idx_tup_read")));
+            statistics->SetItem(pos, 3, stats->GetVal(wxT("idx_tup_fetch")));
+            if (hasSize)
+                statistics->SetItem(pos, 4, stats->GetVal(wxT("size")));
+            stats->MoveNext();
+            pos++;
+        }
+
+        delete stats;
+    }
+}