node以更快的搜索速度嵌入数据库

时间:2017-09-22 08:18:46

标签: sql node.js database nosql

实际上我正在使用SQlite存储一些"文件列表"有一些属性,没有关系数据只有一个文件有多个数据,所以我认为任何关系或nosql数据库对我有效。 现在的问题是搜索的速度,我需要使用Node嵌入数据库并将文件存储在项目文件夹中,实际上我正在使用节点sqlite3,但我测试了更好的-sqlite3模块,结果类似

我的表结构是这样的:

╔════╦══════════════╦══════════╦════════════════╦═════════╦═══════════════╦══════════════════╗
║ id ║     hash     ║   name   ║   description  ║   date  ║      tags     ║    languages     ║
╠════╬══════════════╬══════════╣════════════════╣═════════╣═══════════════╣══════════════════╣
║INT ║     TEXT     ║   TEXT   ║     TEXT       ║  NUMBER ║     JSON      ║       JSON       ║
║  2 ║ b2b22b2b2bb2 ║ two test ║  lorem ipsum b ║ 1233123 ║ ["d","e","f"] ║ ["ko","en","tk"] ║
║  3 ║ asdasdasdsad ║ 333 test ║  lorem ipsum c ║ 1233123 ║ ["a","d","c"] ║ ["es","de","fr"] ║
║  4 ║ 4s342s423424 ║ 444 test ║  lorem ipsum d ║ 1233123 ║ ["a","b","g"] ║ ["es","pt","fr"] ║
╚════╩══════════════╩══════════╩════════════════╩═════════╩═══════════════╩══════════════════╝

arround 300.000行的结果是:

Select * from files WHERE name LIKE "%string%":300毫秒

select * from files WHERE (tags LIKE '"music"' OR tags LIKE '"banana"') AND (languages LIKE '"esp"' OR languages LIKE '"ger"'):400毫秒

select id from files:130毫秒(尝试使用"选择计数(id)作为计数器FROM文件",它的速度较慢,计算结果为30ms vs 150ms)

结果还不错......但这里只有一个搜索操作,我的程序允许多个用户同时搜索,因此搜索时间变得难以辨认。 (10个客户,每回复约4秒) 我在Core i7 4820K中运行测试,用500Gb SSD(550R / 450W)移动到HDD RAID0增加了很多查询次数

我尝试为每个搜索列创建indexx,此项目中的插入是ocassional所以我不太关心插入速度,但是很奇怪,因为在名称,标签或语言字段中放置一个索引并不是很容易速度(仅限50ms,但明显增加了表格大小)

所以..我正在寻找替代方案,我需要一个节点嵌入DB具有极高的搜索速度而且没有数据库锁定(我认为随着时间的推移,DB可以增长到2M行),但是不会消耗大量的内存,不关心是否是关系还是不关系。

编辑:我做了很多测试,这是我的结果:

对于node-lmdb,创建速度非常快,就像使用memcache一样,在4秒内完成100,000次插入,并且读取数据工作正常,但因为是一个键值数据库我需要转换给定数据JSON然后进行"搜索"逻辑,这会大大减少结果,这里是一个示例代码:

const crypto = require('crypto')
const lmdb = require('node-lmdb')

const env = new lmdb.Env()

env.open({
    path: __dirname + "/mydata",
    mapSize: 2*1024*1024*1024, // maximum database size 
    maxDbs: 3
})

var dbi = env.openDbi({
    name: "myPrettyDatabase",
    create: true // will create if database did not exist 
})

// Begin transaction
var txn = env.beginTxn()

let t0 = new Date().getTime()


// Create cursor
let cursor = new lmdb.Cursor(txn, dbi)
let counter = 0
let find = 0

for (var found = cursor.goToFirst(); found !== null; found = 
cursor.goToNext()) {
    cursor.getCurrentString(function(key, data) {

        let js
        try {
            js = JSON.parse(data)
            counter++
        } catch (e) { js = null }

        if (js && String(js.name).indexOf('Lorem') !== -1) {
            find++
        }
    })
}

console.log('counter: ' + counter)
console.log('find: ' + find)

// Close cursor
cursor.close();


let t1 = new Date().getTime()
console.log('time: ' + (t1-t0))


// Commit transaction
txn.commit()

dbi.close()

结果是:

$ node index.js 柜台:215548 发现:113073 时间:1516

列表速度是200ms,但是JSON转换和litle"搜索"逻辑在sqlite速度下慢下来(或者我做错了)

我用Tingodb进行了其他实验,这是一个嵌入式数据库,但是像MongoDB这样的系统,我插入这样的200K对象:

{ hash: '3736b5da857a4c7b9b046f326004803a',
  name: 'inia, looked up one of the more obscure Latin words, consectetur, from a Lorem I',
  description: ', looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of ',
  tags: [ 'pc', 'pc', 'hd', 'mp4' ],
  languages: [ 'fre', 'jap', 'deu' ] }

插入是令人难以置信的,在2 ces中是100K,但是......这是实验:

const Db = require('tingodb')({cacheSize: 60000, cacheMaxObjSize: 4096}).Db
const assert = require('assert')
const crypto = require('crypto')
var db = new Db('./', {})

// Fetch a collection to insert document into 
var collection = db.collection("batch_document_insert_collection_safe")

let t0 = new Date().getTime()
collection.find({ tags: 'video' }).toArray(function(err, docs) {
    console.log(err)  
    console.log(docs)  
    let t1 = new Date().getTime()
    console.log('time: ' + (t1-t0))
})

以200K DB的成本运行,总共38个SECONDSs不知道是否正常......

关于aladb,我测试它并且运行良好,我做了另一个实验(现在我没有)并且性能很好并且类似于sqlite3有一些不错的东西,但是在某些搜索中是比2x慢sqlite(使用LIKE%string%kill the engine)。

编辑2:在linux机器上使用ab命令(ab -n 10000 -c 50 http://machine.tst:13375/library/search?tags=lorem)进行了多次研究和测试以模拟多个请求之后,我终于继续使用sqlite3库但是在启动时创建了一个aditional表(内存一)并存储表(id(INT), hash(VARCHAR), object(TEXT), last(NUMBER))中处理的请求响应。

我第一次使用请求数据创建一个唯一的哈希(" GET" +" / a / b / c" + JSON(requestData))并且json编码响应,现在第一次查询继续以正常速度返回,但下一个就像使用memcache或类似的DB,现在我从10个请求/秒到~450个请求/秒,CPU使用率为10%。

无论如何,我做一个观察者事件,检查"最后"缓存行的列,以删除旧请求和防止内存问题,我检查只有一个请求有多次更改params,所有其他请求总是相同,所以我认为内存使用量不会增长太多。

如果将来我找到了比sqlite3更好的嵌入选项,我尝试更改数据库引擎

1 个答案:

答案 0 :(得分:2)

使用LMDB

尝试Node-LMDB

性能非常好,对于您的用例,它看起来是理想的。我可以为每个客户端实现1,000,000行/秒。

相关问题