【问题标题】:Trying to run 3 SQL statements on Node.js + SQLite getting abysmal performance尝试在 Node.js + SQLite 上运行 3 条 SQL 语句,性能极差
【发布时间】:2023-03-22 06:44:02
【问题描述】:

我有一个 127MB 的 SQLite 数据库,非常简单,只有一张表和 8 列,看起来像这样:

CREATE TABLE stocks (Ticker text, Date text,  Open real, High real, Low real, Close real, Volume integer, Change real);

使用 Node.js,我试图在我的数据库上执行这 3 个 SQL 语句:

SELECT DISTINCT ticker FROM stocks
SELECT close,date from stocks where ticker=? order by date asc
UPDATE stocks set change=? where ticker=? and date=?

它们都嵌套在 foreach 中(即,对于第一个语句的每个结果,我执行第二个语句,对于第二个语句的每个结果,我执行第三个语句)。

我尝试过使用两个模块:(dblite & node-sqlite3)。使用 dblite,我在 sqlite 上获得了 100% 的 CPU 负载,让它运行了 24 小时并且数据库文件保持不变。使用 node-sqlite3 我在 Node.js 上获得 100% 的 CPU 负载 并且没有结果。

dblite的来源:

var dblite = require('dblite'),
    db = dblite('asx.db');

db.query(
  'SELECT DISTINCT ticker FROM stocks',  function (err, tickers) {
    if(err) console.log(err);
    console.log('Got '+tickers.length+' tickers.');
    tickers.forEach(function(ticker) {
        db.query('SELECT close,date from stocks where ticker=? order by date asc',ticker, function(err, rows) {
                if(err) console.log(err);
                var count = 0;
                var previousClose = 0;
                rows.forEach(function(row) {
                        if (count>0) {
                                var change = ((((row[0]-previousClose)/previousClose))*100).toFixed(2);
                                db.query('UPDATE stocks set change=? where ticker=? and date=?',[change,ticker,row[1]], function(err) {
                                        if(err) console.log(err);
                                });

                        }
                        previousClose = row[0];
                        count++;
                });
        });
    });
  }
);

node-sqlite3的来源:

var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('asx.db');

db.each(
  'SELECT DISTINCT ticker FROM stocks',  function (err, tickers) {
    if(err) console.log(err);
        var count = 0;
        var previousClose = 0;
        db.each('SELECT close,date from stocks where ticker=? order by date asc',tickers.Ticker, function(err, row) {
                if(err) console.log(err);
                        if (count>0) {
                                var change = ((((row.Close-previousClose)/previousClose))*100).toFixed(2);
                                db.run('UPDATE stocks set change=? where ticker=? and date=?',[change,tickers.Ticker,row.Date], function(err) {
                                        if(err) console.log(err);
                                });
                        }
                        previousClose = row.Close;
                        count++;
                });
        });

我知道我的嵌套查询导致了指数级的复杂性,但我认为它不应该花这么长时间来执行。我想我做错了什么。我怎么解决这个问题?我应该以与 Perl 同步的方式重写我的代码,还是应该从 SQLite 切换到 MySQL?

谢谢。

【问题讨论】:

  • 查询太多了。有没有理由你不能用一个更复杂的查询来做到这一点?顺便说一句,您看到节点使用sqlite3 消耗CPU 和sqlite 使用dblite 消耗CPU 的原因是dblite 连接到外部sqlite 进程,而sqlite3 在节点进程本身中运行数据库。
  • “我认为不应该花这么长时间来执行”——你有什么证据证明这一点?你用另一种语言做过吗?你知道它执行了多少查询吗?
  • 我认为数据库设计可能是有序的。首先,不要存储计算值。其次,不要将日期存储为文本。
  • 好的,所以切换到另一个 DBMS 没有帮助?我不知道如何更改我的查询以减少查询次数。将日期从文本切换到整数有帮助吗?我需要存储计算的值,因为稍后我将按它进行排序。

标签: sql node.js sqlite


【解决方案1】:

我能够让它工作(我认为仍然是 100% 的 CPU 负载,但至少数据库文件正在更新)。我按照 Dan Bracuk 的想法将所有日期更改为整数,然后将前两个 SQL 语句合并为一个。 我尝试使用 sqlite3,但它总是内存不足。然后我切换到 dblite,这就是我现在正在使用的。这是工作代码:

var dblite = require('dblite'),
db = dblite('asx.db');
var count = 0;
var previousClose = 0;
var previousTicker = '';
db.query('SELECT ticker,close,date from stocks order by ticker, date asc',function(err, rows) {
     if(err) console.log(err);
     rows.forEach(function(row) {
          if (previousTicker !== row[0]) {
               count = 0;
               previousClose = 0;
               previousTicker = row[0];
          }
          if (count>0) {
               var change = ((((row[1]-previousClose)/previousClose))*100).toFixed(2);
               db.query('UPDATE stocks set change=? where ticker=? and date=?',[change,row[0],row[2]], function(err) {
                     if(err) console.log(err);
               });
          }
          previousClose = row[1];
          count++;
     });
});

【讨论】:

  • 数据库总行数:1740034。
【解决方案2】:

使用索引可以加快查找和排序操作。

对于这些特定的陈述,以下索引会很有用:

CREATE INDEX stocks_ticker_date_idx ON stocks(ticker, date);

【讨论】:

    猜你喜欢
    • 2019-07-31
    • 1970-01-01
    • 2018-01-01
    • 2014-10-25
    • 1970-01-01
    • 2016-07-15
    • 2023-02-09
    • 2012-10-11
    • 2011-08-13
    相关资源
    最近更新 更多