IGNITE-4821 Implemented enforce join order option on query tab.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/94c1e7cb Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/94c1e7cb Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/94c1e7cb Branch: refs/heads/ignite-1192 Commit: 94c1e7cb505e0a40e1d3c28de5a25b5aefbd55c0 Parents: f361da4 Author: Vasiliy Sisko <vsi...@gridgain.com> Authored: Wed Mar 15 11:43:23 2017 +0700 Committer: Andrey Novikov <anovi...@gridgain.com> Committed: Wed Mar 15 11:43:23 2017 +0700 ---------------------------------------------------------------------- modules/web-console/backend/app/agent.js | 14 ++++++- modules/web-console/backend/app/browser.js | 8 ++-- .../frontend/app/modules/agent/agent.module.js | 10 +++-- .../frontend/app/modules/sql/sql.controller.js | 25 ++++++++++--- .../frontend/public/stylesheets/style.scss | 8 +++- .../web-console/frontend/views/sql/sql.tpl.pug | 39 +++++++++++++------- 6 files changed, 74 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/backend/app/agent.js ---------------------------------------------------------------------- diff --git a/modules/web-console/backend/app/agent.js b/modules/web-console/backend/app/agent.js index b4394b7..f65eabb 100644 --- a/modules/web-console/backend/app/agent.js +++ b/modules/web-console/backend/app/agent.js @@ -227,17 +227,27 @@ module.exports.factory = function(_, fs, path, JSZip, socketio, settings, mongo, * @param {String} cacheName Cache name. * @param {String} query Query. * @param {Boolean} nonCollocatedJoins Flag whether to execute non collocated joins. + * @param {Boolean} enforceJoinOrder Flag whether enforce join order is enabled. * @param {Boolean} local Flag whether to execute query locally. * @param {int} pageSize Page size. * @returns {Promise} */ - fieldsQuery(demo, nid, cacheName, query, nonCollocatedJoins, local, pageSize) { + fieldsQuery(demo, nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, local, pageSize) { const cmd = new Command(demo, 'exe') .addParam('name', 'org.apache.ignite.internal.visor.compute.VisorGatewayTask') .addParam('p1', nid) .addParam('p2', 'org.apache.ignite.internal.visor.query.VisorQueryTask'); - if (nonCollocatedJoins) { + if (enforceJoinOrder) { + cmd.addParam('p3', 'org.apache.ignite.internal.visor.query.VisorQueryArgV3') + .addParam('p4', cacheName) + .addParam('p5', query) + .addParam('p6', nonCollocatedJoins) + .addParam('p7', enforceJoinOrder) + .addParam('p8', local) + .addParam('p9', pageSize); + } + else if (nonCollocatedJoins) { cmd.addParam('p3', 'org.apache.ignite.internal.visor.query.VisorQueryArgV2') .addParam('p4', cacheName) .addParam('p5', query) http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/backend/app/browser.js ---------------------------------------------------------------------- diff --git a/modules/web-console/backend/app/browser.js b/modules/web-console/backend/app/browser.js index 56f2acc..00ae751 100644 --- a/modules/web-console/backend/app/browser.js +++ b/modules/web-console/backend/app/browser.js @@ -98,9 +98,9 @@ module.exports.factory = (_, socketio, agentMgr, configure) => { }); // Execute query on node and return first page to browser. - socket.on('node:query', (nid, cacheName, query, distributedJoins, local, pageSize, cb) => { + socket.on('node:query', (nid, cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize, cb) => { agentMgr.findAgent(accountId()) - .then((agent) => agent.fieldsQuery(demo, nid, cacheName, query, distributedJoins, local, pageSize)) + .then((agent) => agent.fieldsQuery(demo, nid, cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize)) .then((res) => cb(null, res)) .catch((err) => cb(_errorToJson(err))); }); @@ -114,13 +114,13 @@ module.exports.factory = (_, socketio, agentMgr, configure) => { }); // Execute query on node and return full result to browser. - socket.on('node:query:getAll', (nid, cacheName, query, distributedJoins, local, cb) => { + socket.on('node:query:getAll', (nid, cacheName, query, distributedJoins, enforceJoinOrder, local, cb) => { // Set page size for query. const pageSize = 1024; agentMgr.findAgent(accountId()) .then((agent) => { - const firstPage = agent.fieldsQuery(demo, nid, cacheName, query, distributedJoins, local, pageSize) + const firstPage = agent.fieldsQuery(demo, nid, cacheName, query, distributedJoins, enforceJoinOrder, local, pageSize) .then(({result}) => { if (result.key) return Promise.reject(result.key); http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/app/modules/agent/agent.module.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/agent/agent.module.js b/modules/web-console/frontend/app/modules/agent/agent.module.js index c0e92d5..724fc6c 100644 --- a/modules/web-console/frontend/app/modules/agent/agent.module.js +++ b/modules/web-console/frontend/app/modules/agent/agent.module.js @@ -265,12 +265,13 @@ class IgniteAgentMonitor { * @param {String} cacheName Cache name. * @param {String} [query] Query if null then scan query. * @param {Boolean} nonCollocatedJoins Flag whether to execute non collocated joins. + * @param {Boolean} enforceJoinOrder Flag whether enforce join order is enabled. * @param {Boolean} local Flag whether to execute query locally. * @param {int} pageSize * @returns {Promise} */ - query(nid, cacheName, query, nonCollocatedJoins, local, pageSize) { - return this._rest('node:query', nid, maskNull(cacheName), maskNull(query), nonCollocatedJoins, local, pageSize) + query(nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, local, pageSize) { + return this._rest('node:query', nid, maskNull(cacheName), maskNull(query), nonCollocatedJoins, enforceJoinOrder, local, pageSize) .then(({result}) => { if (_.isEmpty(result.key)) return result.value; @@ -284,11 +285,12 @@ class IgniteAgentMonitor { * @param {String} cacheName Cache name. * @param {String} [query] Query if null then scan query. * @param {Boolean} nonCollocatedJoins Flag whether to execute non collocated joins. + * @param {Boolean} enforceJoinOrder Flag whether enforce join order is enabled. * @param {Boolean} local Flag whether to execute query locally. * @returns {Promise} */ - queryGetAll(nid, cacheName, query, nonCollocatedJoins, local) { - return this._rest('node:query:getAll', nid, maskNull(cacheName), maskNull(query), nonCollocatedJoins, local); + queryGetAll(nid, cacheName, query, nonCollocatedJoins, enforceJoinOrder, local) { + return this._rest('node:query:getAll', nid, maskNull(cacheName), maskNull(query), nonCollocatedJoins, enforceJoinOrder, local); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/app/modules/sql/sql.controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/modules/sql/sql.controller.js b/modules/web-console/frontend/app/modules/sql/sql.controller.js index c082d4e..7ded2d5 100644 --- a/modules/web-console/frontend/app/modules/sql/sql.controller.js +++ b/modules/web-console/frontend/app/modules/sql/sql.controller.js @@ -34,6 +34,8 @@ const SCAN_CACHE_WITH_FILTER_CASE_SENSITIVE = 'VISOR_SCAN_CACHE_WITH_FILTER_CASE const NON_COLLOCATED_JOINS_SINCE = '1.7.0'; +const ENFORCE_JOIN_VERS = [['1.7.9', '1.8.0'], ['1.8.4', '1.9.0'], ['1.9.1']]; + const _fullColName = (col) => { const res = []; @@ -1336,7 +1338,8 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', agentMonitor.awaitAgent() .then(() => _closeOldQuery(paragraph)) .then(() => args.localNid || _chooseNode(args.cacheName, false)) - .then((nid) => agentMonitor.query(nid, args.cacheName, args.query, args.nonCollocatedJoins, !!args.localNid, args.pageSize)) + .then((nid) => agentMonitor.query(nid, args.cacheName, args.query, args.nonCollocatedJoins, + args.enforceJoinOrder, !!args.localNid, args.pageSize)) .then(_processQueryResult.bind(this, paragraph, false)) .catch((err) => paragraph.errMsg = err.message); }; @@ -1369,8 +1372,18 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', return false; }; + $scope.enforceJoinOrderAvailable = (paragraph) => { + const cache = _.find($scope.caches, {name: paragraph.cacheName}); + + if (cache) + return !!_.find(cache.nodes, (node) => Version.includes(node.version, ...ENFORCE_JOIN_VERS)); + + return false; + }; + $scope.execute = (paragraph, local = false) => { const nonCollocatedJoins = !!paragraph.nonCollocatedJoins; + const enforceJoinOrder = !!paragraph.enforceJoinOrder; $scope.actionAvailable(paragraph, true) && _chooseNode(paragraph.cacheName, local) .then((nid) => { @@ -1390,6 +1403,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', pageSize: paragraph.pageSize, maxPages: paragraph.maxPages, nonCollocatedJoins, + enforceJoinOrder, localNid: local ? nid : null }; @@ -1397,7 +1411,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', ActivitiesData.post({ action: '/queries/execute' }); - return agentMonitor.query(nid, args.cacheName, qry, nonCollocatedJoins, local, args.pageSize); + return agentMonitor.query(nid, args.cacheName, qry, nonCollocatedJoins, enforceJoinOrder, local, args.pageSize); }) .then((res) => { _processQueryResult(paragraph, true, res); @@ -1450,7 +1464,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', ActivitiesData.post({ action: '/queries/explain' }); - return agentMonitor.query(nid, args.cacheName, args.query, false, false, args.pageSize); + return agentMonitor.query(nid, args.cacheName, args.query, false, !!paragraph.enforceJoinOrder, false, args.pageSize); }) .then(_processQueryResult.bind(this, paragraph, true)) .catch((err) => { @@ -1488,7 +1502,7 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', ActivitiesData.post({ action: '/queries/scan' }); - return agentMonitor.query(nid, args.cacheName, query, false, local, args.pageSize); + return agentMonitor.query(nid, args.cacheName, query, false, false, local, args.pageSize); }) .then((res) => _processQueryResult(paragraph, true, res)) .catch((err) => { @@ -1609,7 +1623,8 @@ export default ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', const args = paragraph.queryArgs; return Promise.resolve(args.localNid || _chooseNode(args.cacheName, false)) - .then((nid) => agentMonitor.queryGetAll(nid, args.cacheName, args.query, !!args.nonCollocatedJoins, !!args.localNid)) + .then((nid) => agentMonitor.queryGetAll(nid, args.cacheName, args.query, !!args.nonCollocatedJoins, + !!args.enforceJoinOrder, !!args.localNid)) .then((res) => _export(paragraph.name + '-all.csv', paragraph.gridOptions.columnDefs, res.columns, res.rows)) .catch(Messages.showError) .then(() => paragraph.ace && paragraph.ace.focus()); http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/public/stylesheets/style.scss ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/public/stylesheets/style.scss b/modules/web-console/frontend/public/stylesheets/style.scss index ab7e3dd..a07472e 100644 --- a/modules/web-console/frontend/public/stylesheets/style.scss +++ b/modules/web-console/frontend/public/stylesheets/style.scss @@ -809,7 +809,7 @@ button.form-control { } .btn-group { - vertical-align:top; + vertical-align: top; margin-left: 10px; i { line-height: 18px; } @@ -1854,6 +1854,12 @@ th[st-sort] { display: inline-block; } +.panel-top-align { + label { + vertical-align: top !important; + } +} + button.dropdown-toggle { margin-right: 5px; } http://git-wip-us.apache.org/repos/asf/ignite/blob/94c1e7cb/modules/web-console/frontend/views/sql/sql.tpl.pug ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/views/sql/sql.tpl.pug b/modules/web-console/frontend/views/sql/sql.tpl.pug index 931d632..bc134a6 100644 --- a/modules/web-console/frontend/views/sql/sql.tpl.pug +++ b/modules/web-console/frontend/views/sql/sql.tpl.pug @@ -91,20 +91,31 @@ mixin paragraph-rename input.form-control(id='paragraph-name-{{paragraph.id}}' ng-model='paragraph.editName' required ng-click='$event.stopPropagation();' ignite-on-enter='renameParagraph(paragraph, paragraph.editName)' ignite-on-escape='paragraph.edit = false') mixin query-settings - label.tipLabel(bs-tooltip data-placement='bottom' data-title='Configure periodical execution of last successfully executed query') Refresh rate: - button.btn.btn-default.fa.fa-clock-o.tipLabel(ng-class='{"btn-info": paragraph.rate && paragraph.rate.installed}' bs-popover data-template-url='{{ $ctrl.paragraphRateTemplateUrl }}' data-placement='left' data-auto-close='1' data-trigger='click') {{rateAsString(paragraph)}} - - label.tipLabel(bs-tooltip data-placement='bottom' data-title='Max number of rows to show in query result as one page') Page size: - button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.pageSize' bs-select bs-options='item for item in pageSizes') - - label.tipLabel(bs-tooltip data-placement='bottom' data-title='Limit query max results to specified number of pages') Max pages: - button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.maxPages' bs-select bs-options='item.value as item.label for item in maxPages') - - label.tipLabel(ng-if='nonCollocatedJoinsAvailable(paragraph)' bs-tooltip data-placement='bottom' data-title='Non-collocated joins is a special mode that allow to join data across cluster without collocation.<br/>\ - Nested joins are not supported for now.<br/>\ - <b>NOTE</b>: In some cases it may consume more heap memory or may take a long time than collocated joins.' data-trigger='hover') - input(type='checkbox' ng-model='paragraph.nonCollocatedJoins') - span Allow non-collocated joins + .panel-top-align + label.tipLabel(bs-tooltip data-placement='bottom' data-title='Configure periodical execution of last successfully executed query') Refresh rate: + button.btn.btn-default.fa.fa-clock-o.tipLabel(ng-class='{"btn-info": paragraph.rate && paragraph.rate.installed}' bs-popover data-template-url='{{ $ctrl.paragraphRateTemplateUrl }}' data-placement='left' data-auto-close='1' data-trigger='click') {{rateAsString(paragraph)}} + + label.tipLabel(bs-tooltip data-placement='bottom' data-title='Max number of rows to show in query result as one page') Page size: + button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.pageSize' bs-select bs-options='item for item in pageSizes') + + label.tipLabel(bs-tooltip data-placement='bottom' data-title='Limit query max results to specified number of pages') Max pages: + button.btn.btn-default.select-toggle.tipLabel(ng-model='paragraph.maxPages' bs-select bs-options='item.value as item.label for item in maxPages') + + .panel-tip-container + .row(ng-if='nonCollocatedJoinsAvailable(paragraph)') + label.tipLabel(bs-tooltip data-placement='bottom' data-title='Non-collocated joins is a special mode that allow to join data across cluster without collocation.<br/>\ + Nested joins are not supported for now.<br/>\ + <b>NOTE</b>: In some cases it may consume more heap memory or may take a long time than collocated joins.' data-trigger='hover') + input(type='checkbox' ng-model='paragraph.nonCollocatedJoins') + span Allow non-collocated joins + .row(ng-if='enforceJoinOrderAvailable(paragraph)') + label.tipLabel(bs-tooltip data-placement='bottom' data-title='Enforce join order of tables in the query.<br/>\ + If <b>set</b> then query optimizer will not reorder tables in join.<br/>\ + <b>NOTE:</b> It is not recommended to enable this property until you are sure that\ + your indexes and the query itself are correct and tuned as much as possible but\ + query optimizer still produces wrong join order.' data-trigger='hover') + input(type='checkbox' ng-model='paragraph.enforceJoinOrder') + span Enforce join order mixin query-actions button.btn.btn-primary(ng-disabled='!actionAvailable(paragraph, true)' ng-click='execute(paragraph)') Execute