/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { Dimension } from 'vs/base/browser/dom'; import { localize } from 'vs/nls'; import { Disposable } from 'vs/base/common/lifecycle'; import { Table } from 'sql/base/browser/ui/table/table'; import { PlanXmlParser } from 'sql/workbench/contrib/queryPlan/browser/planXmlParser'; import { IPanelView, IPanelTab } from 'sql/base/browser/ui/panel/panel'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { attachTableStyler } from 'sql/platform/theme/common/styler'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TableDataView } from 'sql/base/browser/ui/table/tableDataView'; import { TopOperationsState } from 'sql/workbench/common/editor/query/topOperationsState'; import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; const topOperationColumns: Array> = [ { name: localize('topOperations.operation', "Operation"), field: 'operation', sortable: true, width: 300 }, { name: localize('topOperations.object', "Object"), field: 'object', sortable: true }, { name: localize('topOperations.estCost', "Est Cost"), field: 'estCost', sortable: true }, { name: localize('topOperations.estSubtreeCost', "Est Subtree Cost"), field: 'estSubtreeCost', sortable: true }, { name: localize('topOperations.actualRows', "Actual Rows"), field: 'actualRows', sortable: true }, { name: localize('topOperations.estRows', "Est Rows"), field: 'estRows', sortable: true }, { name: localize('topOperations.actualExecutions', "Actual Executions"), field: 'actualExecutions', sortable: true }, { name: localize('topOperations.estCPUCost', "Est CPU Cost"), field: 'estCPUCost', sortable: true }, { name: localize('topOperations.estIOCost', "Est IO Cost"), field: 'estIOCost', sortable: true }, { name: localize('topOperations.parallel', "Parallel"), field: 'parallel', sortable: true }, { name: localize('topOperations.actualRebinds', "Actual Rebinds"), field: 'actualRebinds', sortable: true }, { name: localize('topOperations.estRebinds', "Est Rebinds"), field: 'estRebinds', sortable: true }, { name: localize('topOperations.actualRewinds', "Actual Rewinds"), field: 'actualRewinds', sortable: true }, { name: localize('topOperations.estRewinds', "Est Rewinds"), field: 'estRewinds', sortable: true }, { name: localize('topOperations.partitioned', "Partitioned"), field: 'partitioned', sortable: true } ]; export class TopOperationsTab extends Disposable implements IPanelTab { public readonly title = localize('topOperationsTitle', "Top Operations"); public readonly identifier = 'TopOperationsTab'; public readonly view: TopOperationsView; constructor(@IInstantiationService instantiationService: IInstantiationService) { super(); this.view = this._register(instantiationService.createInstance(TopOperationsView)); } public clear() { this.view.clear(); } } export class TopOperationsView extends Disposable implements IPanelView { private _state?: TopOperationsState; private table: Table; private container = document.createElement('div'); private dataView = new TableDataView(); constructor( @IThemeService private themeService: IThemeService, @IAdsTelemetryService private readonly telemetryService: IAdsTelemetryService ) { super(); this.table = new Table(this.container, { columns: topOperationColumns, dataProvider: this.dataView, sorter: (args) => { this.dataView.sort(args); } }); this._register(this.table); this._register(attachTableStyler(this.table, this.themeService)); this._register(this.dataView.onRowCountChange(() => this.table.updateRowCount())); } public render(container: HTMLElement): void { container.appendChild(this.container); this.telemetryService.sendActionEvent(TelemetryKeys.TelemetryView.ExecutionPlan, TelemetryKeys.TelemetryAction.ViewTopOperations); } public layout(dimension: Dimension): void { this.table.layout(dimension); } public clear() { this.dataView.clear(); } public showPlan(xml: string) { this.state!.xml = xml; this.dataView.clear(); let parser = new PlanXmlParser(xml); let operations = parser.topOperations; let data = operations.map(i => { return { operation: i.title, object: i.indexObject?.title, estCost: i.estimatedOperatorCost, estSubtreeCost: i.subtreeCost, actualRows: i.runtimeInfo?.actualRows, estRows: i.estimateRows, actualExecutions: i.runtimeInfo?.actualExecutions, estCPUCost: i.estimateCpu, estIOCost: i.estimateIo, parallel: i.parallel, actualRebinds: '', estRebinds: i.estimateRebinds, actualRewinds: '', estRewinds: i.estimateRewinds, partitioned: i.partitioned }; }); this.dataView.push(data); } public setState(val: TopOperationsState) { this._state = val; if (this._state.xml) { this.showPlan(this._state.xml); } } public get state(): TopOperationsState | undefined { return this._state; } }