From 6958c9684f6e9b0969c0d37bcac5d047aee37580 Mon Sep 17 00:00:00 2001 From: lsv Date: Thu, 20 Mar 2025 16:08:30 +0500 Subject: [PATCH] Graph query explain optimization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлено два узла Partial GroupAggregate, Finalize GroupAggregate. Добавлено наглядное представление Memoize. Добавлена поддержка колеса мыши. Если в план более 300 узлов, то включается оптимизация отрисовки и возможно появление артефактов при прокрутке экрана. --- ctl/explainCanvas.cpp | 25 ++- ctl/explainShape.cpp | 122 +++++++++++- include/ctl/explainCanvas.h | 18 +- include/images/ex_finalize_aggregate.png | Bin 0 -> 1364 bytes include/images/ex_finalize_aggregate.pngc | 215 +++++++++++++++++++++ include/images/ex_partial_aggregate.png | Bin 0 -> 1387 bytes include/images/ex_partial_aggregate.pngc | 218 ++++++++++++++++++++++ pgAdmin3.vcxproj | 2 + pgAdmin3.vcxproj.filters | 6 + 9 files changed, 600 insertions(+), 6 deletions(-) create mode 100644 include/images/ex_finalize_aggregate.png create mode 100644 include/images/ex_finalize_aggregate.pngc create mode 100644 include/images/ex_partial_aggregate.png create mode 100644 include/images/ex_partial_aggregate.pngc diff --git a/ctl/explainCanvas.cpp b/ctl/explainCanvas.cpp index 0b34b3e..5a1967b 100644 --- a/ctl/explainCanvas.cpp +++ b/ctl/explainCanvas.cpp @@ -21,6 +21,7 @@ BEGIN_EVENT_TABLE(ExplainCanvas, wxShapeCanvas) EVT_MOTION(ExplainCanvas::OnMouseMotion) + EVT_MOUSEWHEEL(ExplainCanvas::OnMouseWhell) END_EVENT_TABLE() @@ -102,7 +103,7 @@ void ExplainCanvas::SetExplainString(const wxString &str) int maxLevel = 0; wxStringTokenizer lines(flt, wxT("\n")); - + bool isstat = false; while (lines.HasMoreTokens()) { wxString tmp = lines.GetNextToken(); @@ -144,6 +145,21 @@ void ExplainCanvas::SetExplainString(const wxString &str) continue; } } + else { + if ((line.StartsWith("Query Identifier:") || + line.StartsWith("Planning:") || + line.StartsWith("Planning Time:") || + line.StartsWith("Execution Time:")) + && !isstat + ) + isstat = true; + else + if (last != rootShape && isstat) { + // all rows append condition + last->SetConditionAndReplaceLabel(line); + continue; + } + } while (last != rootShape && level <= last->GetLevel()) last = last->GetUpper(); @@ -216,9 +232,14 @@ void ExplainCanvas::SetExplainString(const wxString &str) int h = (rootShape->totalShapes * yoffs + y0 * 2 + PIXPERUNIT - 1) / PIXPERUNIT; SetScrollbars(PIXPERUNIT, PIXPERUNIT, w, h); + isneedoptimizedraw = false; + if (rootShape->totalShapes > 300) isneedoptimizedraw = true; } - +void ExplainCanvas::OnMouseWhell(wxMouseEvent& ev) +{ + HandleOnMouseWheel(ev); +} void ExplainCanvas::OnMouseMotion(wxMouseEvent &ev) { ev.Skip(true); diff --git a/ctl/explainShape.cpp b/ctl/explainShape.cpp index 207ec72..7ed166a 100644 --- a/ctl/explainShape.cpp +++ b/ctl/explainShape.cpp @@ -21,6 +21,8 @@ #include #include "images/ex_aggregate.pngc" +#include "images/ex_partial_aggregate.pngc" +#include "images/ex_finalize_aggregate.pngc" #include "images/ex_append.pngc" #include "images/ex_bmp_and.pngc" #include "images/ex_bmp_heap.pngc" @@ -80,6 +82,7 @@ ExplainShape::ExplainShape(const wxImage &bmp, const wxString &description, long { SetBitmap(wxBitmap(bmp)); SetLabel(description, tokenNo, detailNo); + SetDisableLabel(true); kidCount = 0; totalShapes = 0; usedShapes = 0; @@ -135,21 +138,132 @@ void ExplainShape::OnDraw(wxDC &dc) // We do not draw the root shape if (m_rootShape) return; + wxRect trg=GetCanvas()->GetClientRect(); + wxMouseEvent ev; + ev.m_x = 0; + ev.m_y = 0; + wxPoint logPos(ev.GetLogicalPosition(dc)); + ev.m_x = trg.x+trg.width; + ev.m_y = trg.height; + wxPoint logPos2(ev.GetLogicalPosition(dc)); + wxRect cliprect(logPos, logPos2); + double width = 0.0, height = 0.0; + GetBoundingBoxMin(&width,&height); + wxRect sp((int)(GetX()), (int)(GetY()), (int) (width), (int)(height)); + //int x = (int)(GetX() + (width )); + //int y = (int)(GetY() + (height)); + if (!cliprect.Intersects(sp)) { + if (dynamic_cast(GetCanvas())->isneedoptimizedraw) return; + + } + // dynamic bitmap + bool bmpdynamic = false; + wxBitmap bmpm(bmp.GetWidth(),bmp.GetHeight()); + if (label.StartsWith("Memoize")) { + wxPen p = dc.GetPen(); + wxMemoryDC dc2; + dc2.SelectObject(bmpm); + //dc2.SetBackgroundMode(wxBRUSHSTYLE_SOLID); + dc2.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW))); + dc2.Clear(); + int w = bmpm.GetWidth(); + int h = bmpm.GetHeight(); + dc2.DrawRectangle(0, 0, w, h); + wxRegEx r("Hits: (\\d+) Misses: (\\d+) Evictions: (\\d+) Overflows: (\\d+) Memory Usage: (\\d+\\S+)"); + long hit=0, mis=0, evi=0, ovr=0; + wxString mem; + int x = 0, y = 0; + int tw, th; + wxString txt = _("Cache"); + wxFont f(GetCanvas()->GetFont()); + f.SetPointSize(8); + mem = f.GetNativeFontInfoDesc(); + dc2.SetFont(f); + dc2.SetPen(p); + //dc2.SetTextForeground(*wxBLACK); + //dc2.SetTextBackground(*wxWHITE); + dc2.GetTextExtent(txt, &tw, &th); + int border = 2; + y += border; + x = (w - tw) / 2; + dc2.DrawText(txt, x, y); + y += th+ border; + //dc2.DrawText("TEst", 0, 0); + mem = wxEmptyString; + if (r.Matches(condition)) { + hit=StrToLong( r.GetMatch(condition, 1)); + mis = StrToLong(r.GetMatch(condition, 2)); + evi = StrToLong(r.GetMatch(condition, 3)); + ovr = StrToLong(r.GetMatch(condition, 4)); + mem = (r.GetMatch(condition, 5)); + } + wxRect rect(border, y, w - 2 * border, th / 2); + //dc2.DrawRectangle(0, 0, w, h); + if ((mis + hit) > 0) { + int hitwidth = rect.width * hit * 1.0 / (mis + hit); + { + wxDCPenChanger ppen(dc2, *wxTRANSPARENT_PEN); + //wxColour c(wxString("#00FF00")); + wxColour c(*wxGREEN); + wxDCBrushChanger br(dc2, wxBrush(c)); + //dc2.SetBrush(*wxGREEN_BRUSH); + dc2.DrawRectangle(BMP_BORDER, y, hitwidth, rect.height); + dc2.SetPen(dc.GetPen()); + dc2.SetBrush(*wxTRANSPARENT_BRUSH); + dc2.DrawRectangle(rect); + } + y += rect.height + border; + } + else { + wxDCBrushChanger br(dc2, wxBrush(p.GetColour(), wxHATCHSTYLE_BDIAGONAL)); + rect.x = 0; rect.width = w; rect.height = h - y; + dc2.DrawRectangle(rect); + } + if (!mem.IsEmpty()) { + mem = "" + mem; + dc2.DrawText(mem, border, y); + y += th; + } + x = border; + if (evi > 0) { + wxDCBrushChanger br(dc2, wxBrush(*wxBLUE)); + int r = 4; + wxPoint p(x+r,y+r); + dc2.DrawCircle(p, r); + //y + 2 * r + 1; + x += 2 * r + r; + } + if (ovr > 0) { + wxDCBrushChanger br(dc2, wxBrush(*wxRED)); + int r = 4; + wxPoint p(x + r, y + r); + dc2.DrawCircle(p, r); + x += 2 * r + 3; + } + { + wxPen p = dc.GetPen(); + wxDCPenChanger ppen(dc2, wxPen(p.GetColour(), 2)); + //dc2.DrawLine(wxPoint(0, 0), wxPoint(w, h)); + //dc2.DrawLine(wxPoint(w, 0), wxPoint(0, h)); + } + dc2.SelectObject(wxNullBitmap); + bmpdynamic = true; + } int x, y; x = WXROUND(m_xpos - bmp.GetWidth() / 2.0); y = WXROUND(m_ypos - GetHeight() / 2.0); - dc.DrawBitmap(bmp, x, y, true); + if (bmpdynamic) dc.DrawBitmap(bmpm, x, y, true); else dc.DrawBitmap(bmp, x, y, true); int w, h; dc.SetFont(GetCanvas()->GetFont()); - dc.GetTextExtent(label, &w, &h); + dc.GetTextExtent(label.Trim(), &w, &h); x = WXROUND(m_xpos - w / 2.0); y += bmp.GetHeight() + BMP_BORDER; - dc.DrawText(label, x, y); + dc.DrawText(label.Trim(), x, y); } @@ -238,6 +352,8 @@ ExplainShape *ExplainShape::Create(long level, ExplainShape *last, const wxStrin else if (token == wxT("Result")) s = new ExplainShape(*ex_result_png_img, descr); else if (token == wxT("Append")) s = new ExplainShape(*ex_append_png_img, descr); else if (token == wxT("Gather")) s = new ExplainShape(*ex_gatcher_png_img, descr); + else if (token == wxT("Partial") && token2 == wxT("GroupAggregate")) s = new ExplainShape(*ex_partial_aggregate_png_img, descr); + else if (token == wxT("Finalize") && token2 == wxT("GroupAggregate")) s = new ExplainShape(*ex_finalize_aggregate_png_img, descr); else if (token == wxT("Nested")) { if (token2 == wxT("Loop") && token4 == wxT("Join")) diff --git a/include/ctl/explainCanvas.h b/include/ctl/explainCanvas.h index a89bda3..289bd47 100644 --- a/include/ctl/explainCanvas.h +++ b/include/ctl/explainCanvas.h @@ -44,9 +44,11 @@ public: void SetExplainString(const wxString &str); void Clear(); void SaveAsImage(const wxString &fileName, wxBitmapType imageType); - + bool isneedoptimizedraw=false; private: void OnMouseMotion(wxMouseEvent &ev); + void OnMouseWhell(wxMouseEvent& ev); + ExplainShape *rootShape; ExplainPopup *popup; @@ -66,6 +68,20 @@ public: if (condition.Length() == 0) condition = str; else condition += wxT(" ") + str; } + void SetConditionAndReplaceLabel(const wxString& str) + { + wxString replace= "Planning Time:"; + if (!str.StartsWith(replace)) { + replace = "Execution Time:"; + if (!str.StartsWith(replace)) { + condition += wxT(" ") + str; + return; + } + } + condition = label+ wxT(" ") + condition; + label = str; + description = str; + } long GetLevel() { return level; diff --git a/include/images/ex_finalize_aggregate.png b/include/images/ex_finalize_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..7f69a159a91eb2d805192739df4c05b44ab8cb6b GIT binary patch literal 1364 zcmV-a1*`grP)l- z?+l0k$l%H#WsovR8RReH!|NewWTQA=s?!U+f4QC09pw9gp!DT}70%POn2cxSIWs%B z++m?>lZng!&F#Y`-9R{lmq*bo@#vrF`BC)>#WSL z84IF>v7hy0Fq|YelVBl#ckvv-*s!J%hK(=!f>Pg#8P7Z!053@x2`%BXHw*?*!Z@08 zZk7-w+0EP(tUY9zmAl$unES@(@gO|lrXLqf(a+Emu1suYMkq-hT0MeEP$5 zaY2+Yp4I?{DQ5NxZbqrN%VWjVuj*mm`z9ovZSdp%svwT=7tRyy$QVjTu1Rilra7_29rjT!I*Np^?9<)*vO(P7*S?&JfJ#7R5|flq&!hGwm)b zhK3e&gW(?bCDjfsFwLEH7>ndmGkF;Nb_;racFh}~As|{|YFqpy0n(*s5w$Q%kd35h ze2f@j5v6O*ZKrXjiZ?!M=^Z1=V4vH~qLIW`$?PL)vz9XbPLs}Ws^(Si>?O00C^y7u z()Uf37S**@$?WXP5@kA;L9>(BRQ;9&h_Yy$jHS`y)UHPk3ayJ>>WW80%J_+R8m(jr ztqSqr^Cq`>G&s_#*6S{;#-k~;ktGhJ*_CDdx63wM={})aDe5Y9r(!8IRtuV2LJw;~ zq^mt}Ie1J=K2W6;b!$G1Q%tmxI~^6`23h0klo`EUb=Zj~vA(dXs^h3jJLq0CgL71N zM1DIO1Z&OqEpf2acwl$h5m}GJn~LC_OC835C>wP5NI0EyTM-*O90bcuTS;Ix&QWzt zY1{9FP~(tQW%NNzbu;_OEmNlYPOgRz?Vb)hkE&x9cwKflDs6Jhl(rxEY$hzsY~p$M zF0MSQGl&wRpCGo=B0K`?!kgtTy5`pkbcm9KEFG*XpCWyq7IXh=sO0hUFUxqhC5x_3 z9YG2Z6%^RF*Aob*a-H)+H=ZfK!Zn}2<`vgWvkUSWvamY1#-e~_KR^>@zaIw{REsW7 zD@15@7fV?VseBX82#^X|IsOk()) + { + wxMemoryInputStream img_ex_finalize_aggregate_pngIS(ex_finalize_aggregate_png_data, sizeof(ex_finalize_aggregate_png_data)); + img_ex_finalize_aggregate_png->LoadFile(img_ex_finalize_aggregate_pngIS, wxBITMAP_TYPE_PNG); + } + return img_ex_finalize_aggregate_png; +} +#define ex_finalize_aggregate_png_img ex_finalize_aggregate_png_img() + +static wxBitmap *ex_finalize_aggregate_png_bmp() +{ + static wxBitmap *bmp_ex_finalize_aggregate_png; + if (!bmp_ex_finalize_aggregate_png || !bmp_ex_finalize_aggregate_png->IsOk()) + bmp_ex_finalize_aggregate_png = new wxBitmap(*ex_finalize_aggregate_png_img); + return bmp_ex_finalize_aggregate_png; +} +#define ex_finalize_aggregate_png_bmp ex_finalize_aggregate_png_bmp() + +static wxIcon *ex_finalize_aggregate_png_ico() +{ + static wxIcon *ico_ex_finalize_aggregate_png; + if (!ico_ex_finalize_aggregate_png || !ico_ex_finalize_aggregate_png->IsOk()) + { + ico_ex_finalize_aggregate_png = new wxIcon(); + ico_ex_finalize_aggregate_png->CopyFromBitmap(*ex_finalize_aggregate_png_bmp); + } + return ico_ex_finalize_aggregate_png; +} +#define ex_finalize_aggregate_png_ico ex_finalize_aggregate_png_ico() + +#endif // EX_FINALIZE_AGGREGATE_PNG_H diff --git a/include/images/ex_partial_aggregate.png b/include/images/ex_partial_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..5132f9ca1354f2a4cb14ab2475964dd686221b03 GIT binary patch literal 1387 zcmV-x1(f=UP)@=i6)6{u1flxvsgeXJ;1VRc3i3KYV8#ZiMu|;A9`~y4| zl|V?S0#&L25!5cKl%xsRYDviZo#x@-*v`Z6;oPyEj;yrtjK`*-zS7l9Zf3^*`8@9V z&T#mj46Y1P1}TF);2@t|@`)oGrTG$_PT-^0+BwZZej4zK-z*qmJynaza6($sv&p5W zfzEY0F7r3Hzs|F@%yov$nx57S5T)yMy7ax-d)PHrUWb{v03Ou`@lJ0Crzyzbh*$jV zmLA7FF5CztFu#+)b|NKxaC&mE8+B-?Fu*S8@&}iijkVpaVTe4`(Wgz|tB% ze!ZR3+_gTx>=TDKb%@4O&^Ng;uo1=1J`9IPEC#ri))jwXt0Mt@S=zj-x9ujyT~AN7>g(E zW|5RAxtX1UwTCRTa#J}BbKkJpipB;TE?%9*#dk{pB8RDJuEWq~6uUAv>vjlO^eKb6 zGUydAObd9mryk$_Hd8tfIgG7^VEhs6C0VwjG%D!PT_a$QTto@X8(;av_g;JqU;Hwi z7sx9=jER@~Je(#wdltsgT8CkZnZ2x=Q7Z0o7%}x{{xBbY?-S27y7BkqN?yUvK-e)C zMztxkFvkgIBoMf7t!{U;{v+RV*t6f>P< znVWgS9OOPFvq&z?$@UZQZ4nI1W>lKg&_2^qV}$p{q9%o5QDWq7FsB|T7-ktt00KR| zidn|SV^|{?O|#ZvFsBLT))vJ~G9^_2EN0qmMhp!tXl9wB3#%+lb7wt91L@RE9tOAB zfL@om;Ek`O3NZ^)+u|k(5I>q0$pzVnrjA~WCP-UZPBg5@@#aimKoHB1Ysz<76m~ z7OQeSk}I^%cip=sqG+N@S?k`wajR#|BBTJ~!?D8`H z$7K`xx=-Y-6g8E)Q=u4|ss+U@p@W(b@oEQb79JCmw^g-;R5u^SDJI&;oeG8cnXGYP zN{`;IdhCRwSYKFG)p1nS4jKz4aF)uBz+Z(yu-0t<5(h(#17@okf%Pz)u>jtGsiQa` z@&?@)38%AmBSNFaAwmhnML5?!4df@C2oD6p@uN8pd8JLlPMJX3zzb3Sv<%g&i* z7o;O3VU>H2K?ciy01suqUk4Uci!Sak2;b^1mXaJ|nI>E@Kq}}amzXN3BhTFpg1r+N z-`LxSxML0NL8=8k+(;Glj)Xg?7u)t!14e^!DJGJc^IsOk()) + { + wxMemoryInputStream img_ex_partial_aggregate_pngIS(ex_partial_aggregate_png_data, sizeof(ex_partial_aggregate_png_data)); + img_ex_partial_aggregate_png->LoadFile(img_ex_partial_aggregate_pngIS, wxBITMAP_TYPE_PNG); + } + return img_ex_partial_aggregate_png; +} +#define ex_partial_aggregate_png_img ex_partial_aggregate_png_img() + +static wxBitmap *ex_partial_aggregate_png_bmp() +{ + static wxBitmap *bmp_ex_partial_aggregate_png; + if (!bmp_ex_partial_aggregate_png || !bmp_ex_partial_aggregate_png->IsOk()) + bmp_ex_partial_aggregate_png = new wxBitmap(*ex_partial_aggregate_png_img); + return bmp_ex_partial_aggregate_png; +} +#define ex_partial_aggregate_png_bmp ex_partial_aggregate_png_bmp() + +static wxIcon *ex_partial_aggregate_png_ico() +{ + static wxIcon *ico_ex_partial_aggregate_png; + if (!ico_ex_partial_aggregate_png || !ico_ex_partial_aggregate_png->IsOk()) + { + ico_ex_partial_aggregate_png = new wxIcon(); + ico_ex_partial_aggregate_png->CopyFromBitmap(*ex_partial_aggregate_png_bmp); + } + return ico_ex_partial_aggregate_png; +} +#define ex_partial_aggregate_png_ico ex_partial_aggregate_png_ico() + +#endif // EX_PARTIAL_AGGREGATE_PNG_H diff --git a/pgAdmin3.vcxproj b/pgAdmin3.vcxproj index 13f08ef..1a096e4 100644 --- a/pgAdmin3.vcxproj +++ b/pgAdmin3.vcxproj @@ -2159,6 +2159,7 @@ + @@ -2186,6 +2187,7 @@ + diff --git a/pgAdmin3.vcxproj.filters b/pgAdmin3.vcxproj.filters index d1ed2eb..031a748 100644 --- a/pgAdmin3.vcxproj.filters +++ b/pgAdmin3.vcxproj.filters @@ -3961,6 +3961,9 @@ include\images + + include\images + include\images @@ -4036,6 +4039,9 @@ include\images + + include\images + include\images