Open TENCHIANG opened 5 years ago
登陆阿里云, 从控制台选择云数据库MongoDB, 点击实例id进行管理 在连接信息 (Connection String URI)下面找到网络类型->公网->mongodb://root:****@dds-bpxxxxxx, 复制下来把星号替换为root密码
云数据库MongoDB
连接信息 (Connection String URI)
网络类型
公网
mongodb://root:****@dds-bpxxxxxx
连接方式1也就是公网那个地址复制过来的是Primary和Secondary域名都写在一起的方式, 连接方式2也可以直接连Primary就行 Primary显示的是专有网络的域名 其实要连接对应的公网的域名 也就是连接方式1的第一个域名
mongo mongodb://root:****@dds-bpxxxxxxxxxxxx-pub.mongodb.rds.aliyuncs.com:3717,dds-bpyyyyyyyyyyyyyyy-pub.mongodb.rds.aliyuncs.com:3717/admin?replicaSet=mgset-1203073 # 连接方式1 第一个域名就是Primary的公网版本 mongo \ --port 3717 \ -u 'root' \ -p 'xxxxx' \ --authenticationDatabase 'admin' \ dds-bpxxxxxxx-pub.mongodb.rds.aliyuncs.com # 连接方式2 db # 当前数据库 show dbs # 列出所有数据库 use <db_name> show collections # 显示当前数据库所有的collection(表) db.getCollection('xxx').find().pretty() # 显示xxx表里所有的document 方式1 db.xxx.find().pretty() # 显示xxx表里所有的document 方式2 db.system.profile.find().pretty().count() # 统计当前数据库的满查询数量 db.system.profile.find({}, { ns: 1, millis: 1 }).limit(10).sort({ millis: -1 }).pretty() # 10个最慢查询 db.system.profile.find({}, { ns: 1, millis: 1 }).limit(10).sort({ ts: -1 }).pretty() # 最新的10个慢查询 db.stats() # 当前数据库状态
{ command: { find: 'items', filter: { sku: '123456' }, ..., $db: 'test' } } // 等价于 use test db.items.find({ sku: '123456' })
主要是开启Database Profiler记录慢查询, 然后根据db.system.profile.find()来优化代码, 建立索引 MongoDB 查询优化分析 监控mongo 状态慢查询 论MongoDB索引选择的重要性 这里是建议选择createdAt作为索引而不是_id, 因为这样会更快
Database Profiler
db.system.profile.find()
索引
createdAt
_id
MongoDB 用户名密码登录
读写指向不同节点, 节点之间数据同步(binlog) 因为读压力更大, 所以都是一主多从架构
bson是字节数组, 前4字节是表示document的大小, 4字节最大能表示4GB, 也就是说, 单个document最大不超过4GB
查询计划: 就是如何执行查询 explain有3种模式:
以数据库jjqshopdb的users表为例
jjqshopdb
users
use jjqshopdb db.users.count() 11
查看当前表的索引 可以看到, 默认就对_id进行了索引, 名为_id_
_id_
db.users.getIndexes() [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "jjqshopdb.users" } ]
创建索引: createIndex, 当然ensureIndex也可以, 为了兼容老版本MongoDB 3.0以前 注意createIndex({ a: 1, b : 1 })注意不是创建了两个索引a_1、b_1而是创建了一个联合索引a_1_b_1!!!
createIndex
ensureIndex
MongoDB 3.0
createIndex({ a: 1, b : 1 })
a_1
b_1
a_1_b_1
db.users.createIndex({ telephone: 1 }) // 给用户表建立电话的索引 db.users.getIndexes() // 验证 [ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "jjqshopdb.users" }, { "v" : 2, "key" : { "telephone" : 1 }, "name" : "telephone_1", "ns" : "jjqshopdb.users", "background" : true } ]
使用索引进行查询
db.users.find({ telephone: '176xxxx5209' }).explain('executionStats') { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "jjqshopdb.users", "indexFilterSet" : false, "parsedQuery" : { "telephone" : { "$eq" : "176xxxx5209" } }, "winningPlan" : { "stage" : "FETCH", "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "telephone" : 1 }, "indexName" : "telephone_1", // 使用telephone_1索引!!! "isMultiKey" : false, "multiKeyPaths" : { "telephone" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "telephone" : [ "[\"176xxxx5209\", \"176xxxx5209\"]" ] } } }, "rejectedPlans" : [ ] }, "executionStats" : { "executionSuccess" : true, "nReturned" : 1, // 返回1个文档 "executionTimeMillis" : 0, // 非常快 几乎是 0ms "totalKeysExamined" : 1, // 使用了1个索引 "totalDocsExamined" : 1, // 只扫描1个文档 没用之前可能得扫描所有文档 如11 "executionStages" : { "stage" : "FETCH", "nReturned" : 1, "executionTimeMillisEstimate" : 0, "works" : 2, "advanced" : 1, "needTime" : 0, "needYield" : 0, "saveState" : 0, "restoreState" : 0, "isEOF" : 1, "invalidates" : 0, "docsExamined" : 1, "alreadyHasObj" : 0, "inputStage" : { "stage" : "IXSCAN", "nReturned" : 1, "executionTimeMillisEstimate" : 0, "works" : 2, "advanced" : 1, "needTime" : 0, "needYield" : 0, "saveState" : 0, "restoreState" : 0, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "telephone" : 1 }, "indexName" : "telephone_1", "isMultiKey" : false, "multiKeyPaths" : { "telephone" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "telephone" : [ "[\"176xxxx5209\", \"176xxxx5209\"]" ] }, "keysExamined" : 1, "seeks" : 1, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0 } } }, "ok" : 1, "operationTime" : Timestamp(1566976793, 1), "$clusterTime" : { "clusterTime" : Timestamp(1566976793, 1), "signature" : { "hash" : BinData(0,"Q9qoVAZebjbDaoqzMCayySTSpnY="), "keyId" : NumberLong("6683112302490681460") } } }
删除索引 注意dropIndex({ a: 1, b : 1 })注意不是删除了两个索引a_1、b_1而是删除了一个联合索引a_1_b_1!!! 注意删除索引删不了_id_索引, 只能删除表
dropIndex({ a: 1, b : 1 })
db.users.dropIndex('telephone_1') # 索引名 db.users.dropIndex({ telephone: -1 }) # 字段名
比如 查看find命令的源代码
db.orders.find function (query, fields, limit, skip, batchSize, options) { var cursor = new DBQuery(this._mongo, this._db, this, this._fullName, this._massageObject(query), fields, limit, skip, batchSize, options || this.getQueryOptions()); { const session = this.getDB().getSession(); const readPreference = session._serverSession.client.getReadPreference(session); if (readPreference !== null) { cursor.readPref(readPreference.mode, readPreference.tags); } const readConcern = session._serverSession.client.getReadConcern(session); if (readConcern !== null) { cursor.readConcern(readConcern.level); } } return cursor; }
查看db.stats()的源代码, 会发现等价命令db.runCommand({dbstats: 1}) 也就是说可以用db.runCommand()调用任何命令 注意, 里面的this就相当于外面的db
db.stats()
db.runCommand({dbstats: 1})
db.runCommand()
db.stats function (scale) { return this.runCommand({dbstats: 1, scale: scale}); } // 新版本的MongoDB已经不能直观看出db.runCommand的源代码了, 下面是老版本的 db.runCommand function (obj, extra) { if (typeof obj == 'string') { const n = {} n[obj] = 1 obj = n extra && typeof extra == 'object' && Object.keys(extra).forEach(key => { n[key] = extra[x] }) } return this.$cmd.findOne(obj) } db.$cmd.findOne({ dbstats: 1 }) // 相当于db.stats() db.$cmd.findOne('dbstat') // 同上 db.$cmd.findOne({ collstats: 'users' })
所以, 数据库shell命令其实就是在特殊集合$cmd上面的查询 也就是说, 可以在Driver里面通过runCommand运行MongoDB的命令啦
$cmd
名词对照
阿里云找到MongoDB远程连接地址
登陆阿里云, 从控制台选择
云数据库MongoDB
, 点击实例id进行管理 在连接信息 (Connection String URI)
下面找到网络类型
->公网
->mongodb://root:****@dds-bpxxxxxx
, 复制下来把星号替换为root密码连接MongoDB
连接方式1也就是公网那个地址复制过来的是Primary和Secondary域名都写在一起的方式, 连接方式2也可以直接连Primary就行 Primary显示的是专有网络的域名 其实要连接对应的公网的域名 也就是连接方式1的第一个域名
system.profile.command解释
MongoDB慢查询优化
主要是开启
Database Profiler
记录慢查询, 然后根据db.system.profile.find()
来优化代码, 建立索引
MongoDB 查询优化分析 监控mongo 状态慢查询 论MongoDB索引选择的重要性 这里是建议选择createdAt
作为索引而不是_id
, 因为这样会更快MongoDB的find、getMore特性
MongoDB安全相关
MongoDB 用户名密码登录
MongoDB自带工具
数据库高级优化: 数据库拆分、读写分离
数据库拆分
读写分离
读写指向不同节点, 节点之间数据同步(binlog) 因为读压力更大, 所以都是一主多从架构
更新document的代价
bson是字节数组, 前4字节是表示document的大小, 4字节最大能表示4GB, 也就是说, 单个document最大不超过4GB
通过explain查看查询计划
查询计划: 就是如何执行查询 explain有3种模式:
使用createIndex创建索引
以数据库
jjqshopdb
的users
表为例查看当前表的索引 可以看到, 默认就对
_id
进行了索引, 名为_id_
创建索引:
createIndex
, 当然ensureIndex
也可以, 为了兼容老版本MongoDB 3.0
以前 注意createIndex({ a: 1, b : 1 })
注意不是创建了两个索引a_1
、b_1
而是创建了一个联合索引a_1_b_1
!!!使用索引进行查询
删除索引 注意
dropIndex({ a: 1, b : 1 })
注意不是删除了两个索引a_1
、b_1
而是删除了一个联合索引a_1_b_1
!!! 注意删除索引删不了_id_
索引, 只能删除表查看MongoDB的源代码
比如 查看find命令的源代码
MongoDB的shell命令实现原理
查看
db.stats()
的源代码, 会发现等价命令db.runCommand({dbstats: 1})
也就是说可以用db.runCommand()
调用任何命令 注意, 里面的this就相当于外面的db所以, 数据库shell命令其实就是在特殊集合
$cmd
上面的查询 也就是说, 可以在Driver里面通过runCommand运行MongoDB的命令啦