mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-09-07 09:05:55 +00:00
Merge pull request #1752 from molecula/sup-86
[SUP-86] slow webui on large query
This commit is contained in:
commit
2e9b43dfca
8 changed files with 75 additions and 38 deletions
|
|
@ -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('.');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
.queryString {
|
||||
white-space: pre-wrap;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -40,3 +40,8 @@
|
|||
font-size: 0.75rem;
|
||||
color: rgba(var(--contrast-rgb), 0.54);
|
||||
}
|
||||
|
||||
.tooMany {
|
||||
vertical-align: middle;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue