1

I work for a company whose clients are other companies. The company recordset in the DB has 40+ fields with ten thousand plus companies (including one field that holds in most cases a ridiculously long string.) The JSON Data payload that comes back via express and a wildcard SQL call is north of 4 million lines in Postman.

Background:

We had this set up using ASMX Web Services in VB.NET but the response to the client was averaging close to thirty seconds when having to serialize the JSON. It was cumbersome and quite a pain to work with.

Going back to the previous version in .NET MVC it would still sometimes take over ten to fifteen seconds to populate a simple select input with the company name much less than render the UI.

The New Environment:

I have currently constructed the system in its 4th generation using a SERN environment with webpack 3+. I have enabled the API to run with CORS on a separate port(5000) from my app's port(8080) and have tested the payload. It is still 8 seconds. Better but not optimal.

The Question:

How can I speed up the payload? I have heard of React being able to split payloads from Node API's but haven't a clue on how to get that done. Can anyone take the code below and either tell me where I can improve or point me to some libraries or something that can speed up the performance of the SQL call or data transfer?

Current POSTMAN Performance stats: SQL: 2.679 secs Express: 1.331 secs API to Client: 3.976 secs

package.json:

{
  "name": "project",
  "version": "1.0.0",
  "description": "desc",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "start": "concurrently \"webpack-dev-server\" \" node ./server/core/server.js\"",
    "dev": "webpack-dev-server",
    "server": "node ./server/core/server.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/djErock/EMR4.git"
  },
  "author": "Erik Grosskurth",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/djErock/EMR4/issues"
  },
  "homepage": "https://github.com/djErock/EMR4#readme",
  "dependencies": {
    "axios": "^0.16.2",
    "cors": "^2.8.4",
    "jquery": "^3.2.1",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-router-dom": "^4.1.1"
  },
  "devDependencies": {
    "babel-core": "^6.25.0",
    "babel-loader": "^7.1.1",
    "babel-preset-latest": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "concurrently": "^3.5.0",
    "css-loader": "^0.28.4",
    "express": "^4.16.0",
    "file-loader": "^0.11.2",
    "mssql": "^4.1.0",
    "react-hot-loader": "^3.0.0-beta.7",
    "style-loader": "^0.18.2",
    "webpack": "^3.6.0",
    "webpack-dev-middleware": "^1.12.0",
    "webpack-dev-server": "^2.9.1"
  }
}

Webpack.config:

var webpack = require('webpack');
var path = require('path');

module.exports = {
  entry: [
    'react-hot-loader/patch',
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/only-dev-server',
    './src/index.js'
  ],
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      }
    ],
  },
  devServer: {
    historyApiFallback: true,
    hot: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
  ]
};

Server.js

const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');

const config = require('../../webpack.config.js');
const options = {
  contentBase: './dist',
  hot: true
};

var app = require('express')();
var cors = require('cors');

app.use(function (req, res, next) {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
  res.setHeader('Access-Control-Allow-Credentials', true);
  // Pass to next layer of middleware
  next();
});

const companies = require("../controllers/company.js");
app.get('/api/companies', function (req, res) {
  companies.getCompanyList(req, res);
});


webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);

app.listen(5000, () => {
  console.log('dev server listening on port 5000');
});

comapny.js

var db = require("../core/db");

exports.getCompanyList = function(req, resp) {
    db.execSQL("SELECT * FROM tblCompany", function(data, err) {
        if (err) {
            resp.writeHead(500, "Internal Error Occurred",{"Content-Type": "application/json"});
            resp.write(JSON.stringify(err));
        }else {
            resp.writeHead(200, {"Content-Type": "application/json"});
            resp.write(JSON.stringify(data));
        }
        resp.end();
    });
}

DB.js

var sqlDB = require("mssql");
var settings = require("../settings.js");

exports.execSQL = function(sql, callback) {

    var conn = new sqlDB.ConnectionPool(settings.dbConfig);
    conn.connect().then(function() {

        var req = new sqlDB.Request(conn);
        req.query(sql).then(function(recordset) {
            callback(recordset);
        }).catch(function(err) {
            console.log(err);
            callback(null, err);
        });

    }).catch(function(err) {
        console.log(err);
        callback(null, err);
    });

};

React with axios ajax call in component:

  handleOnChange(e) {
    e.preventDefault();
    //Let's call the caduceus server
    axios.get(Constants.WS_PREFIX+'companies')
    .then(function (response) {
      console.log(response);
    })
    .catch(function (error) {
      console.log(error);
    });
  }
Erik Grosskurth
  • 3,762
  • 5
  • 29
  • 44
  • Have you tried pagination? See [this question](https://stackoverflow.com/questions/109232/what-is-the-best-way-to-paginate-results-in-sql-server) – Mike Eason Oct 03 '17 at 15:27
  • How would pagination work two ways? I need all the data just at intervals of its displayed. Think Facebook newsfeed... – Erik Grosskurth Oct 03 '17 at 17:20
  • Also how do I populate a select input (that works as a search filter BTW) with 10k results without slowing down. Pagination wouldn't work right? – Erik Grosskurth Oct 03 '17 at 17:22
  • I would think pagination could work if you new the total amount of returned results but would that require some sort of async call for DB data based on the component? – Erik Grosskurth Oct 03 '17 at 17:28

1 Answers1

-1

You'd need to have pagination implemented in the api and should use limit-offset in your queries.

  • 1
    Can you provide more info and code examples on how to achieve what you are describing? – Romeo Jun 26 '22 at 20:19