Merge pull request #1752 from molecula/sup-86

[SUP-86] slow webui on large query
This commit is contained in:
reese 2021-11-04 12:54:11 -05:00 committed by GitHub
commit 2e9b43dfca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 38 deletions

View file

@ -18,6 +18,7 @@ export type ResultType = {
roundtrip: number;
index?: string;
error: string;
totalMessageCount: number;
};
let streamingResults: ResultType = {
@ -27,11 +28,15 @@ let streamingResults: ResultType = {
headers: [],
rows: [],
roundtrip: 0,
error: ''
error: '',
totalMessageCount: 0,
};
export const QueryContainer: FC<{}> = () => {
let startTime: Moment;
const MAX_MESSAGES = 1000; // same limit as in query builder
const [indexes, setIndexes] = useState<any>();
const [results, setResults] = useState<ResultType[]>([]);
const [errorResult, setErrorResult] = useState<ResultType>();
@ -44,12 +49,15 @@ export const QueryContainer: FC<{}> = () => {
});
const handleQueryMessages = (message: RowResponse) => {
const response = message.toObject();
if (response.headersList.length > 0) {
streamingResults.headers = response.headersList;
streamingResults.duration = response.duration;
if (streamingResults.totalMessageCount < MAX_MESSAGES) {
const response = message.toObject();
if (response.headersList.length > 0) {
streamingResults.headers = response.headersList;
streamingResults.duration = response.duration;
}
streamingResults.rows.push(response.columnsList);
}
streamingResults.rows.push(response.columnsList);
streamingResults.totalMessageCount += 1;
};
const handleQueryEnd = (status: grpc.Code, statusMessage: string) => {
@ -91,7 +99,8 @@ export const QueryContainer: FC<{}> = () => {
rows: [],
index,
roundtrip: 0,
error: ''
error: '',
totalMessageCount: 0,
};
startTime = moment();
if (query) {
@ -115,10 +124,10 @@ export const QueryContainer: FC<{}> = () => {
if (word.includes('-')) {
let wordArr = word.split('.');
wordArr.forEach((section, idx) => {
if(section.includes('-') && !word.includes('`')) {
if (section.includes('-') && !word.includes('`')) {
wordArr[idx] = `\`${wordArr[idx]}\``;
}
})
});
queryArr[idx] = wordArr.join('.');
}
});

View file

@ -30,7 +30,6 @@
.queryString {
white-space: pre-wrap;
display: block;
font-size: 12px;
}

View file

@ -20,7 +20,7 @@ type QueryResultsProps = {
export const QueryResults: FC<QueryResultsProps> = ({
collapsibleQuery = true,
results,
onRemoveResult
onRemoveResult,
}) => {
const [showQuery, setShowQuery] = useState<boolean>(false);
const [copyTooltip, setCopyTooltip] = useState<string>('Copy Query');
@ -142,7 +142,12 @@ export const QueryResults: FC<QueryResultsProps> = ({
{results.operation === 'GroupBy' && results.rows.length <= 50 ? (
<GroupByChart results={results} />
) : (
<DataTable headers={headers} data={data} autoWidth={true} />
<DataTable
headers={headers}
data={data}
autoWidth={true}
totalResultsCount={results.totalMessageCount}
/>
)}
</Fragment>
);

View file

@ -23,7 +23,7 @@ export const GroupByChart: FC<GroupByChartType> = ({ results }) => {
groupData = {
...groupData,
[headers[0].name]: row[0][`${headers[0].datatype}val`],
[secondaryValue]: row[2][`${headers[2].datatype}val`]
[secondaryValue]: row[2][`${headers[2].datatype}val`],
};
if (!uniqueKeys.includes(secondaryValue.toString())) {
@ -33,7 +33,7 @@ export const GroupByChart: FC<GroupByChartType> = ({ results }) => {
groupData = {
...groupData,
[headers[0].name]: row[0][`${headers[0].datatype}val`],
value: secondaryValue
value: secondaryValue,
};
}
});
@ -58,15 +58,15 @@ export const GroupByChart: FC<GroupByChartType> = ({ results }) => {
? {
textColor: 'var(--text-secondary)',
axis: {
domain: { line: { stroke: 'rgba(255, 255, 255, 0.1)' } }
domain: { line: { stroke: 'rgba(255, 255, 255, 0.1)' } },
},
grid: { line: { stroke: 'rgba(255, 255, 255, 0.1)' } },
tooltip: { container: { background: '#1c2022' } }
tooltip: { container: { background: '#1c2022' } },
}
: {
axis: {
domain: { line: { stroke: '#dddddd' } }
}
domain: { line: { stroke: '#dddddd' } },
},
}
}
groupMode="grouped"
@ -76,7 +76,7 @@ export const GroupByChart: FC<GroupByChartType> = ({ results }) => {
tickRotation: -40,
legend: headers[0].name,
legendPosition: 'middle',
legendOffset: 80
legendOffset: 80,
}}
axisLeft={{
tickSize: 5,
@ -84,7 +84,7 @@ export const GroupByChart: FC<GroupByChartType> = ({ results }) => {
tickRotation: 0,
legend: 'count',
legendPosition: 'middle',
legendOffset: -40
legendOffset: -40,
}}
tooltip={({ id, value, color }) => (
<strong style={{ color }}>
@ -113,11 +113,11 @@ export const GroupByChart: FC<GroupByChartType> = ({ results }) => {
{
on: 'hover',
style: {
itemOpacity: 1
}
}
]
}
itemOpacity: 1,
},
},
],
},
]}
animate={true}
motionStiffness={90}

View file

@ -32,7 +32,8 @@ let streamingResults: ResultType = {
headers: [],
rows: [],
roundtrip: 0,
error: ''
error: '',
totalMessageCount: 0,
};
export const QueryBuilderContainer = () => {
@ -109,7 +110,7 @@ export const QueryBuilderContainer = () => {
const dateTime = moment().unix();
const element = document.createElement('a');
const file = new Blob([exportRows.join('\n')], {
type: 'text/plain;charset=utf-8'
type: 'text/plain;charset=utf-8',
});
element.href = URL.createObjectURL(file);
element.download = `molecula-${results?.index}-${dateTime}.csv`;
@ -133,7 +134,8 @@ export const QueryBuilderContainer = () => {
rows: [],
index: table,
roundtrip: 0,
error: ''
error: '',
totalMessageCount: 0,
};
startTime = moment();
setLoading(true);

View file

@ -19,13 +19,15 @@ type TableProps = {
data: any[];
loading?: boolean;
autoWidth?: boolean;
totalResultsCount: number;
};
export const DataTable: FC<TableProps> = ({
headers,
data,
loading = false,
autoWidth = false
autoWidth = false,
totalResultsCount,
}) => {
const [sortedData, setSortedData] = useState<any[]>(data);
const [sort, setSort] = useState<string>(headers[0]?.name);
@ -55,7 +57,7 @@ export const DataTable: FC<TableProps> = ({
if (resultsRef.current) {
resultsRef.current.scrollIntoView({
behavior: 'smooth',
block: 'start'
block: 'start',
});
}
}, 0);
@ -70,8 +72,6 @@ export const DataTable: FC<TableProps> = ({
}
};
return (
<Fragment>
<div ref={resultsRef} />
@ -86,14 +86,14 @@ export const DataTable: FC<TableProps> = ({
>
<span
className={classNames(css.sortable, {
[css.currentSort]: sort === col.name
[css.currentSort]: sort === col.name,
})}
onClick={() => onSortClick(col.name)}
>
{col.name}
<ArrowDropDownIcon
className={classNames(css.sortArrow, {
[css.asc]: sortDir === 'asc'
[css.asc]: sortDir === 'asc',
})}
/>
</span>
@ -120,7 +120,7 @@ export const DataTable: FC<TableProps> = ({
className={css.tableCell}
>
{formatTableCell(row, col)}
</TableCell>
</TableCell>
))}
{autoWidth ? <TableCell className={css.fillWidth} /> : null}
</TableRow>
@ -148,7 +148,6 @@ export const DataTable: FC<TableProps> = ({
</TableBody>
</Table>
</div>
<Pager
className={css.pagination}
page={page}
@ -157,6 +156,7 @@ export const DataTable: FC<TableProps> = ({
showTotal={true}
onChangePage={onChangePage}
onChangePerPage={onChangePerPage}
totalResultsCount={totalResultsCount}
/>
</Fragment>
);

View file

@ -40,3 +40,8 @@
font-size: 0.75rem;
color: rgba(var(--contrast-rgb), 0.54);
}
.tooMany {
vertical-align: middle;
margin-right: .5em;
}

View file

@ -1,4 +1,6 @@
import React, { FC } from 'react';
import ErrorOutlineIcon from '@material-ui/icons/ErrorOutline';
import Tooltip from '@material-ui/core/Tooltip';
import classNames from 'classnames';
import Pagination from '@material-ui/lab/Pagination';
import Pluralize from 'react-pluralize';
@ -13,6 +15,7 @@ type PagerProps = {
className?: any;
onChangePage: (page: number) => void;
onChangePerPage?: (rowsPerPage: number) => void;
totalResultsCount?: number;
};
export const Pager: FC<PagerProps> = ({
@ -22,7 +25,8 @@ export const Pager: FC<PagerProps> = ({
showTotal = true,
className,
onChangePage,
onChangePerPage
onChangePerPage,
totalResultsCount = 0,
}) => {
const numPages = Math.ceil(totalItems / rowsPerPage);
const startResults = (page - 1) * rowsPerPage + 1;
@ -45,7 +49,7 @@ export const Pager: FC<PagerProps> = ({
options={[
{ label: '10', value: '10' },
{ label: '25', value: '25' },
{ label: '50', value: '50' }
{ label: '50', value: '50' },
]}
onChange={(value) => onChangePerPage(Number(value))}
fullWidth
@ -55,6 +59,19 @@ export const Pager: FC<PagerProps> = ({
</div>
{showTotal && (
<div className={css.total}>
{totalResultsCount > 1000 && (
<span className={css.tooMany}>
<Tooltip
title={
'This query has ' +
totalResultsCount +
' results. Due to browser memory limitations, you will only be able to view the first 1000.'
}
>
<ErrorOutlineIcon fontSize="small" color="error" />
</Tooltip>
</span>
)}
Showing {startResults} - {endResults} of{` `}
<Pluralize singular="result" count={totalItems} />
</div>