#include "explaintreemodelitem.h" #include "json/json.h" #include namespace { ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan) { ExplainTreeModelItemPtr result = std::make_shared(); result->setNodeType(QString::fromStdString(plan["Node Type"].asString())); result->setStrategy(QString::fromStdString(plan["Strategy"].asString())); result->setJoinType(QString::fromStdString(plan["Join Type"].asString())); result->setStartupCost(plan["Startup Cost"].asFloat()); result->setTotalCost(plan["Total Cost"].asFloat()); result->setEstimatedRows(plan["Plan Rows"].asInt()); result->setPlanWidth(plan["Plan Width"].asInt()); result->setActualStartupTime(plan["Actual Startup Time"].asFloat()); result->setActualTotalTime(plan["Actual Total Time"].asFloat()); result->setActualRows(plan["Actual Rows"].asInt()); result->setActualLoops(plan["Actual Loops"].asInt()); result->setRelationName(QString::fromStdString(plan["Relation Name"].asString())); result->setAlias(QString::fromStdString(plan["Alias"].asString())); result->setScanDirection(QString::fromStdString(plan["Scan Direction"].asString())); result->setIndexName(QString::fromStdString(plan["Index Name"].asString())); result->setIndexCondition(QString::fromStdString(plan["Index Cond"].asString())); result->setIndexRecheck(QString::fromStdString(plan["Rows Removed by Index Recheck"].asString())); result->setFilter(QString::fromStdString(plan["Filter"].asString())); result->setHashCondition(QString::fromStdString(plan["Hash Cond"].asString())); result->setSortKey(QString::fromStdString(plan["Sort Key"].toStyledString())); result->setSortMethod(QString::fromStdString(plan["Sort Method"].asString())); if (plan.isMember("Sort Space Used")) { const Json::Value& sm = plan["Sort Space Used"]; if (sm.isInt()) { result->setSortSpaceUsed(sm.asInt()); } } result->setSortSpaceType(QString::fromStdString(plan["Sort Space Type"].asString())); Json::Value &plans = plan["Plans"]; if (plans.isArray()) { for (auto p : plans) { result->appendChild( createPlanItemFromJson(p)); } } return result; } } // END of unnamed namespace ExplainRoot::SPtr ExplainRoot::createFromJson(Json::Value &json) { auto res = std::make_shared(); // Explain always seems to be an array with one element if (json.isArray()) { if (json.size() > 0) { Json::Value &explain = json[0]; Json::Value &plan = explain["Plan"]; res->plan = createPlanItemFromJson(plan); res->planningTime = explain["Planning Time"].asFloat(); res->executionTime = explain["Execution Time"].asFloat(); res->totalRuntime = explain["Total Runtime"].asFloat(); } } return res; } ExplainTreeModelItem::ExplainTreeModelItem() = default; ExplainTreeModelItem::~ExplainTreeModelItem() = default; void ExplainTreeModelItem::appendChild(ItemPtr child) { child->setParent(shared_from_this()); m_childItems.push_back(child); } ExplainTreeModelItemPtr ExplainTreeModelItem::child(int row) { return m_childItems.at(row); } int ExplainTreeModelItem::childCount() const { return m_childItems.size(); } //int ExplainTreeModelItem::columnCount() const //{ // return 6; //} //QVariant ExplainTreeModelItem::data(int column) const //{ // QVariant r; // if (column == 0) { // r = nodeType; // } // else if (column == 1) { // } // return r; //} int ExplainTreeModelItem::row() const { int idx = 0; auto p = m_parentItem.lock(); if (p) { idx = std::find(p->m_childItems.begin(), p->m_childItems.end(), shared_from_this()) - p->m_childItems.begin(); } return idx; } void ExplainTreeModelItem::setParent(ItemPtr parent) { m_parentItem = parent; } ExplainTreeModelItemPtr ExplainTreeModelItem::parent() { auto p = m_parentItem.lock(); return p; } void ExplainTreeModelItem::setNodeType(QString nt) { m_nodeType = std::move(nt); } const QString& ExplainTreeModelItem::nodeType() const { return m_nodeType; } void ExplainTreeModelItem::setStrategy(QString strat) { m_strategy = std::move(strat); } const QString& ExplainTreeModelItem::strategy() const { return m_strategy; } void ExplainTreeModelItem::setJoinType(QString jointype) { m_joinType = jointype; } QString ExplainTreeModelItem::joinType() const { return m_joinType; } void ExplainTreeModelItem::setStartupCost(float cost) { m_startupCost = cost; } void ExplainTreeModelItem::setTotalCost(float cost) { m_totalCost = cost; } void ExplainTreeModelItem::setEstimatedRows(long long estimated) { m_estimatedRows = estimated; } long long ExplainTreeModelItem::estimatedRows() const { return m_estimatedRows; } void ExplainTreeModelItem::setPlanWidth(int width) { m_planWidth = width; } void ExplainTreeModelItem::setActualStartupTime(float timems) { m_actualStartupTime = timems; } void ExplainTreeModelItem::setActualTotalTime(float timems) { m_actualTotalTime = timems; } float ExplainTreeModelItem::actualTotalTime() const { return m_actualTotalTime; } void ExplainTreeModelItem::setActualRows(long long rowcount) { m_actualRows = rowcount; } long long ExplainTreeModelItem::actualRows() const { return m_actualRows; } void ExplainTreeModelItem::setActualLoops(int loopcount) { m_actualLoops = loopcount; } int ExplainTreeModelItem::actualLoops() const { return m_actualLoops; } void ExplainTreeModelItem::setRelationName(QString n) { m_relationName = std::move(n); } void ExplainTreeModelItem::setAlias(QString a) { m_alias = std::move(a); } void ExplainTreeModelItem::setScanDirection(QString dir) { m_scanDirection = std::move(dir); } void ExplainTreeModelItem::setIndexName(QString idxname) { m_indexName = std::move(idxname); } void ExplainTreeModelItem::setIndexCondition(QString idxcond) { m_indexCondition = std::move(idxcond); } void ExplainTreeModelItem::setIndexRecheck(QString idxrecheck) { m_indexRecheck = std::move(idxrecheck); } void ExplainTreeModelItem::setFilter(QString filter) { m_filter = std::move(filter); } void ExplainTreeModelItem::setHashCondition(QString condition) { m_hashCondition = std::move(condition); } void ExplainTreeModelItem::setSortKey(QString key) { m_sortKey = std::move(key); } void ExplainTreeModelItem::setSortMethod(QString method) { m_sortMethod = std::move(method); } void ExplainTreeModelItem::setSortSpaceUsed(int space) { m_sortSpaceUsed = space; } void ExplainTreeModelItem::setSortSpaceType(QString type) { m_sortSpaceType = std::move(type); } float ExplainTreeModelItem::exclusiveTime() const { float tt = inclusiveTime(); for (auto c : m_childItems) { tt -= c->inclusiveTime(); } return tt; } float ExplainTreeModelItem::inclusiveTime() const { float t = m_actualTotalTime * m_actualLoops; return t; } float ExplainTreeModelItem::estimateError() const { float res = 1.0; if (m_estimatedRows > m_actualRows) { if (m_actualRows > 0) { res = float(m_estimatedRows) / m_actualRows; } else { res = std::numeric_limits::infinity(); } } else if (m_actualRows > m_estimatedRows) { if (m_estimatedRows > 0) { res = float(m_actualRows) / m_estimatedRows; } else { res = std::numeric_limits::infinity(); } res = -res; } return res; } QString ExplainTreeModelItem::detailString() const { QString s; if (!m_joinType.isEmpty()) { s += m_joinType + " " + m_nodeType + " "; } if (!m_strategy.isEmpty()) { s += m_strategy + " " + m_nodeType + " "; } if (!m_indexName.isEmpty()) { s+= m_scanDirection + " " + m_nodeType + "\n"; if (!m_indexCondition.isEmpty()) { s += "cond: " + m_indexCondition + " "; } if (!m_filter.isEmpty()) { s += "filter: " + m_filter + "\n"; } if (!m_indexRecheck.isEmpty()) { s += "removed by recheck: " + m_indexRecheck + "\n"; } s += "idx: " + m_indexName + " rel: " + m_alias + " "; } else { if (!m_alias.isEmpty()) { s += m_nodeType + " rel: " + m_alias + " "; } } if (!m_hashCondition.isEmpty()) { s += m_hashCondition + " "; } if (!m_sortMethod.isEmpty()) { s += m_sortMethod + " " + m_sortSpaceType + " " + QString::number(m_sortSpaceUsed) + "kB " + m_sortKey + " "; } return s.trimmed(); } //"Sort Key": ["pg_attribute.attname"], //"Sort Method": "quicksort", //"Sort Space Used": 1426, //"Sort Space Type": "Memory", //{ // "Node Type": "Index Scan", // "Parent Relationship": "Inner", // "Scan Direction": "Forward", // "Index Name": "pg_type_oid_index", // "Relation Name": "pg_type", // "Alias": "pg_type", // "Startup Cost": 0.15, // "Total Cost": 0.18, // "Plan Rows": 1, // "Plan Width": 758, // "Actual Startup Time": 0.003, // "Actual Total Time": 0.004, // "Actual Rows": 1, // "Actual Loops": 100, // "Index Cond": "(oid = pg_attribute.atttypid)", // "Rows Removed by Index Recheck": 0 // "Filter": "actief" //}