【发布时间】: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 没有帮助?我不知道如何更改我的查询以减少查询次数。将日期从文本切换到整数有帮助吗?我需要存储计算的值,因为稍后我将按它进行排序。