diff --git a/docs/docs/reference/Monitor-Processor.md b/docs/docs/reference/Monitor-Processor.md new file mode 100644 index 00000000..a61978b2 --- /dev/null +++ b/docs/docs/reference/Monitor-Processor.md @@ -0,0 +1,72 @@ +--- +template: overrides/main.html +--- + +This document mainly introduces how we use the Processor monitoring function provided by the software. + +##### Redirect + +--- + +After the mouse moves to the `Monitor` menu, a drop-down box will automatically pop up. Select the `Processor` sub-menu in the drop-down box and click it, and it will jump to the corresponding management page. His snapshot is similar to the following screenshot: + +![](https://images.edurt.io/2021/11/02/16358536985404.jpg) + +> By default, the selection item after `Server` on the top left is blank, you need to manually select a data source + +##### Execute + +--- + +On the right side of the top menu, there will be a `Threshold` (unit/ms) value input window, which is used for our update time interval. When we turn on the `Auto` function on the right, the software will input the value according to `Threshold` Automatically refresh the data. + +![](https://images.edurt.io/2021/11/02/16358538862636.jpg) + +The chart in the middle part is used to mark the total number of processes of the current query of the currently selected server. The chart has a maximum of 20 points by default, and each time point will automatically cover the previous expired data points. + +![](https://images.edurt.io/2021/11/02/16358539745671.jpg) + +The bottom data table is used to render the detailed process of the server's specific query at our current time. It provides the following indicators: + +- `Time`: The time the current process is running +- `Rows`: The number of rows to be queried in the current process query (`read_rows`+`written_rows`) +- `Elapsed`: Process query time (unit/ms) +- `Bytes`: The bytes consumed by the current process query (`read_bytes`+`written_bytes`) +- `memoryUsage`: Memory consumed by the query +- `bytesRead`: Query the number of bytes read +- `bytesWritten`: Query the number of bytes written +- `hash`: The hash of this query +- `host`: The host name of the service being queried + +> The above data are from the `system.processes` table + +##### Action + +--- + +We also provide two operations in the detailed list: + +- `KILL`: Stop the current query (**Note: This operation cannot be rolled back**) +- `DDL`: Query the specific SQL statement of the current query + +###### Kill + +When our query takes a long time, we can click the button, and it will A window like the following pops up: + +![](https://images.edurt.io/2021/11/02/16358546469724.jpg) + +The window gives us two important tips, which need to be read carefully. If you are sure to perform the operation, enter the unique data marked under the `Necessary` prompt in the input box, and then click the `OK` button. + +It will send a KILL command to the server, the specific command executed is as follows + +```sql +KILL QUERY WHERE query_id = 'f57ae2a8-8aeb-4f71-b395-43d7065ac564' +``` + +###### DDL + +When we need to view the specific SQL of this query, we can click the button, and it will A window like the following pops up: + +![](https://images.edurt.io/2021/11/02/16358548788950.jpg) + +The editor is the specific SQL statement we query this time. diff --git a/docs/docs/release/1.9.0-20211130.md b/docs/docs/release/1.9.0-20211130.md new file mode 100644 index 00000000..c8b8adbe --- /dev/null +++ b/docs/docs/release/1.9.0-20211130.md @@ -0,0 +1,25 @@ +--- +template: overrides/main.html +--- + +DBM Version for 1.9.0 is released! + +#### Docs + +--- + +- Add monitor/processor documentation + +#### Enhancement + +--- + +- Support truncate table +- Support clean table by partition +- Support optimize table + +#### UI + +--- + +- Add a link to the GitHub source code repository in the navigation diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 0d5868d2..d6f1c214 100755 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -12,7 +12,7 @@ copyright: Copyright © 2021 EdurtIO theme: name: null - custom_dir: !ENV [THEME_DIR, "material"] + custom_dir: !ENV [ THEME_DIR, "material" ] static_templates: - 404.html @@ -24,19 +24,19 @@ theme: features: - content.code.annotate - content.tabs.link -# - header.autohide -# - navigation.expand + # - header.autohide + # - navigation.expand - navigation.indexes -# - navigation.instant + # - navigation.instant - navigation.sections - navigation.tabs -# - navigation.tabs.sticky + # - navigation.tabs.sticky - navigation.top - navigation.tracking - search.highlight - search.share - search.suggest -# - toc.integrate + # - toc.integrate palette: - scheme: default primary: indigo @@ -105,9 +105,12 @@ markdown_extensions: nav: - Home: index.md - Getting started: - - Datasource: reference/1.Get-Started-Datasource.md - - Query: reference/2.Get-Started-Query.md + - Datasource: reference/1.Get-Started-Datasource.md + - Query: reference/2.Get-Started-Query.md + - Monitor: + - Processor: reference/Monitor-Processor.md - Release Note: + - 1.9.0: release/1.9.0-20211130.md - 1.8.0: release/1.8.0-2021-11-02.md - 1.7.0: release/1.7.0-2021-10-09.md - 1.6.0: release/1.6.0.md diff --git a/package.json b/package.json index 366d5e04..e0388a42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dbm", - "version": "1.8.0", + "version": "1.9.0", "author": "qianmoQ ", "description": "ClickHouse DataBase Manager Tools", "credits": "EdurtIO", diff --git a/src/renderer/i18n/en_US.js b/src/renderer/i18n/en_US.js index 8bebd6b1..eb43536b 100644 --- a/src/renderer/i18n/en_US.js +++ b/src/renderer/i18n/en_US.js @@ -102,7 +102,12 @@ export default { mysql: 'MySQL', experimental: 'Experimental', version: 'Version', - description: 'Description' + description: 'Description', + truncate: 'Truncate', + clean: 'Clean', + partition: 'Partition', + optimize: 'Optimize', + final: 'Final' }, prompt: { component: { @@ -163,7 +168,8 @@ export default { service_not_available: 'The current service is not available. Please check the configuration or remove it!', service_available: 'The current service is available for query or other operations!', refresh_config: 'After the configuration is modified, it needs to be reloaded manually!', - experimental: 'This is an experimental feature that should not be used in production.' + experimental: 'This is an experimental feature that should not be used in production.', + truncate_table: 'This operation deletes all data, but does not delete the table!' }, tooltip: { is_empty: 'Is not empty', diff --git a/src/renderer/i18n/zh_CN.js b/src/renderer/i18n/zh_CN.js index 64f21c85..9141d84d 100644 --- a/src/renderer/i18n/zh_CN.js +++ b/src/renderer/i18n/zh_CN.js @@ -102,7 +102,12 @@ export default { mysql: 'MySQL', experimental: '实验', version: '版本', - description: '描述' + description: '描述', + truncate: '截断', + clean: '清理', + partition: '分区', + optimize: '优化', + final: 'Final' }, prompt: { component: { @@ -163,7 +168,8 @@ export default { service_not_available: '当前服务不可用。请检查配置或将其删除!', service_available: '当前服务可用于查询或其他操作!', refresh_config: '配置修改后需要手动重新载入!', - experimental: '这是一个试验性特性,不应该在生产中使用。' + experimental: '这是一个试验性特性,不应该在生产中使用。', + truncate_table: '该操作将会删除所有数据,但是不会进行表的删除!' }, tooltip: { is_empty: '是否非空', diff --git a/src/renderer/services/ContextMenu.js b/src/renderer/services/ContextMenu.js index 50f33928..9218e7eb 100644 --- a/src/renderer/services/ContextMenu.js +++ b/src/renderer/services/ContextMenu.js @@ -3,6 +3,7 @@ import i18n from '../i18n' const StringUtils = require('../utils/StringUtils') const Support = require('../utils/Support') const ServerContextMenu = require('./ContextMenu/ServerContextMenu') +const TableContextMenu = require('./ContextMenu/TableContextMenu') export function getContextMenu(type) { if (StringUtils.isEmpty(type)) { @@ -34,28 +35,7 @@ export function getContextMenu(type) { }) break case Support.TABLE: - deleted.type = Support.TABLE - menus.push(deleted, { - name: StringUtils.format('{0}{1}', [i18n.t('common.add'), i18n.t('common.column')]), - command: Support.ADD, - icon: Support.ADD_ICON, - type: Support.TABLE - }, { - name: i18n.t('common.ddl'), - command: Support.DDL, - icon: Support.DDL_ICON, - type: Support.TABLE - }, { - name: i18n.t('common.preview'), - command: Support.PREVIEW, - icon: Support.PREVIEW_ICON, - type: Support.TABLE - }, { - name: StringUtils.format('{0}{1}', [i18n.t('common.rename'), i18n.t('common.table')]), - command: Support.EDIT, - icon: Support.EDIT_ICON, - type: Support.TABLE - }) + menus = TableContextMenu.getContextMenu(Support.TABLE) break case Support.COLUMN: deleted.type = Support.COLUMN diff --git a/src/renderer/services/ContextMenu/TableContextMenu.js b/src/renderer/services/ContextMenu/TableContextMenu.js new file mode 100644 index 00000000..9a04a49f --- /dev/null +++ b/src/renderer/services/ContextMenu/TableContextMenu.js @@ -0,0 +1,56 @@ +import i18n from '../../i18n' + +/** + * Right-click menus available for table + */ + +const Support = require('../../utils/Support') +const StringUtils = require('../../utils/StringUtils') + +export function getContextMenu(type) { + const menus = [] + if (type === Support.TABLE) { + menus.push({ + name: i18n.t('common.delete'), + command: Support.DELETE, + type: Support.TABLE, + icon: Support.DELETE_ICON + }, { + name: StringUtils.format('{0}{1}', [i18n.t('common.add'), i18n.t('common.column')]), + command: Support.ADD, + icon: Support.ADD_ICON, + type: Support.TABLE + }, { + name: i18n.t('common.ddl'), + command: Support.DDL, + icon: Support.DDL_ICON, + type: Support.TABLE + }, { + name: i18n.t('common.preview'), + command: Support.PREVIEW, + icon: Support.PREVIEW_ICON, + type: Support.TABLE + }, { + name: StringUtils.format('{0}{1}', [i18n.t('common.rename'), i18n.t('common.table')]), + command: Support.EDIT, + icon: Support.EDIT_ICON, + type: Support.TABLE + }, { + name: StringUtils.format('{0}{1}', [i18n.t('common.truncate'), i18n.t('common.table')]), + command: Support.TRUNCATE, + icon: Support.TRUNCATE_ICON, + type: Support.TABLE + }, { + name: StringUtils.format('{0}{1}', [i18n.t('common.clean'), i18n.t('common.table')]), + command: Support.CLEAN, + icon: Support.CLEAN_ICON, + type: Support.TABLE + }, { + name: StringUtils.format('{0}{1}', [i18n.t('common.optimize'), i18n.t('common.table')]), + command: Support.OPTIMIZE, + icon: Support.OPTIMIZE_ICON, + type: Support.TABLE + }) + } + return menus +} diff --git a/src/renderer/services/Table.js b/src/renderer/services/Table.js index bba87679..22cd5fea 100644 --- a/src/renderer/services/Table.js +++ b/src/renderer/services/Table.js @@ -70,3 +70,45 @@ WHERE export function renameTable(server, sql) { return getQuery(server, sql) } + +export function truncateTable(server, database, table) { + const sql = StringUtils.format('TRUNCATE TABLE {0}.{1}', [database, table]) + return getQuery(server, sql) +} + +export function getPartitions(server, database, table) { + const sql = StringUtils.format(` +SELECT + DISTINCT "partition" AS "partition", + "database", + "table", + name, + active +FROM + "system".parts +WHERE + "database" = '{0}' + AND "table" = '{1}' +ORDER BY + modification_time DESC`, [database, table]) + return getQuery(server, sql) +} + +export function cleanTableByPartition(server, database, table, partition) { + const sql = StringUtils.format(`ALTER TABLE {0}.{1} DROP PARTITION '{2}'`, + [database, table, partition]) + return getQuery(server, sql) +} + +export function optimizeTable(server, database, table, type, final, partition) { + let sql = StringUtils.format('OPTIMIZE TABLE {0}.{1}', [database, table]) + if (type) { + sql = StringUtils.format(`{0} PARTITION ID '{1}'`, [sql, partition]) + } else { + sql = StringUtils.format(`{0} PARTITION '{1}'`, [sql, partition]) + } + if (final) { + sql = StringUtils.format('{0} FINAL', [sql]) + } + return getQuery(server, sql) +} diff --git a/src/renderer/utils/Support.js b/src/renderer/utils/Support.js index f7928492..d6a6c8aa 100644 --- a/src/renderer/utils/Support.js +++ b/src/renderer/utils/Support.js @@ -7,8 +7,12 @@ export const ADD = 'ADD' export const ADD_ICON = 'plus-circle' export const DELETE = 'DELETE' export const DELETE_ICON = 'minus-circle' +export const TRUNCATE = 'TRUNCATE' +export const TRUNCATE_ICON = 'trash' export const INFO = 'INFO' export const INFO_ICON = 'info-circle' +export const CLEAN = 'CLEAN' +export const CLEAN_ICON = 'minus-circle' export const PREVIEW = 'PREVIEW' export const PREVIEW_ICON = 'eye' export const DDL = 'DDL' @@ -16,6 +20,8 @@ export const DDL_ICON = 'search' export const EDIT = 'EDIT' export const RENAME = 'RENAME' export const EDIT_ICON = 'edit' +export const OPTIMIZE = 'OPTIMIZE' +export const OPTIMIZE_ICON = 'gavel' export const PROCESSES = 'PROCESSES' export const CONNECTIONS = 'CONNECTIONS' diff --git a/src/renderer/views/Data/Metadata/index.vue b/src/renderer/views/Data/Metadata/index.vue index ef849196..13d05bcc 100644 --- a/src/renderer/views/Data/Metadata/index.vue +++ b/src/renderer/views/Data/Metadata/index.vue @@ -74,6 +74,9 @@ @close="loading.tableColumn = false"> + + + @@ -106,11 +109,17 @@ import ModifyColumn from '../../components/Column/Modify' import RenameColumn from '../../components/Column/Rename' import PreviewColumn from '../../components/Column/Preview' import DatabaseDdl from '../../components/Database/Ddl' +import TableTruncate from '../../components/Table/Truncate' +import TableClean from '../../components/Table/Clean' +import TableOptimize from '../../components/Table/Optimize' const Support = require('../../../utils/Support') export default { components: { + TableOptimize, + TableClean, + TableTruncate, DatabaseDdl, PreviewColumn, RenameColumn, @@ -151,6 +160,9 @@ export default { tablePreview: false, tableColumn: false, tableRename: false, + tableOptimize: false, + tableTruncate: false, + tableClean: false, addColumn: false, modifyColumn: false, renameColumn: false, @@ -220,6 +232,12 @@ export default { if (value.command === Support.DELETE && value.type === Support.TABLE) { this.loading.deleteTable = true } + if (value.command === Support.TRUNCATE && value.type === Support.TABLE) { + this.loading.tableTruncate = true + } + if (value.command === Support.CLEAN && value.type === Support.TABLE) { + this.loading.tableClean = true + } if (value.command === Support.DDL && value.type === Support.TABLE) { this.ddl.visible = true this.handlerShowDDL(this.treeValue.server, this.treeValue.database, this.treeValue.table) @@ -230,6 +248,9 @@ export default { if (value.command === Support.EDIT && value.type === Support.TABLE) { this.loading.tableRename = true } + if (value.command === Support.OPTIMIZE && value.type === Support.TABLE) { + this.loading.tableOptimize = true + } if (value.command === Support.ADD && value.type === Support.TABLE) { this.loading.addColumn = true } diff --git a/src/renderer/views/components/Table/Clean/index.vue b/src/renderer/views/components/Table/Clean/index.vue new file mode 100644 index 00000000..1e17a6f5 --- /dev/null +++ b/src/renderer/views/components/Table/Clean/index.vue @@ -0,0 +1,91 @@ + + + diff --git a/src/renderer/views/components/Table/Optimize/index.vue b/src/renderer/views/components/Table/Optimize/index.vue new file mode 100644 index 00000000..61652da9 --- /dev/null +++ b/src/renderer/views/components/Table/Optimize/index.vue @@ -0,0 +1,112 @@ + + + diff --git a/src/renderer/views/components/Table/Truncate/index.vue b/src/renderer/views/components/Table/Truncate/index.vue new file mode 100644 index 00000000..1b187ad4 --- /dev/null +++ b/src/renderer/views/components/Table/Truncate/index.vue @@ -0,0 +1,61 @@ + + + diff --git a/src/renderer/views/layout/components/Sidebar/index.vue b/src/renderer/views/layout/components/Sidebar/index.vue index ac6af9d2..2925e234 100644 --- a/src/renderer/views/layout/components/Sidebar/index.vue +++ b/src/renderer/views/layout/components/Sidebar/index.vue @@ -1,80 +1,90 @@