SQL Server简介

Posted 苦海123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server简介相关的知识,希望对你有一定的参考价值。

SQL Server是微软的一款关系型数据库。某些平台吹得天花烂坠,今天第一次在自己的项目中使用了下,感觉不是那么好,特别是SQL语句的支持度还是很欠缺,如limit等都不支持,还有特别单双引号都是需要特别注意的,下面是SQL Server的安装和使用总结:
SQL Server安装:
1.到官网下载下载器:https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads ,如图:

2.新建一个文件夹并将下载好的下载器移动到这个文件夹中(可以不新建,个人习惯将软件归类管理,但是后面会发现微软的软件很多你是无法很好的管理,因为它会不受控制的安装到C盘去,即使自定义了安装目录,但是还是有很多文件是装到C盘去,吐槽微软!),之后双击下载器后选中基本即可,如:

3.双击基本后会再次弹出一个许可协议,接受后将安装路径修改为自己新建的文件夹,之后点击安装继续,如:

4.看到下面界面表示数据库已经安装成功,此时可以继续安装SSMS(SSMS是一款数据库管理软件,类似SQLyog,但是没有SQLyog好用的数据库管理软件),如:

5.点击完SSMS后会跳到新的网页中去,此时点击如图所示位置即可下载可视化管理软件(如果需要中文,可以继续到下面Available languages点击chinese即可安装中文版),如:

6.将下载好的SSMS下载器放到重新新建的文件夹,之后双击,并修改安装路径后继续点击install进行下载安装,如:

7.安装完成后点击Close即可,点击完CLose后,此时桌面可能没有快捷方式,此时你可以到自己应用中找到名为:azuredatastudio.exe的程序之后双击即可,通过文件所在位置可以看到文件是安装在了C盘,我C盘坚决不安装与系统相关的软件,因此我会将整个文件剪切到其它盘,之后创建快捷方式,打开管理软件如下(类似编辑器,如果想要更可视化的管理数据库,那么还得继续选择其中的工具):

其中的工具如:

**node.js中使用SQL Server: **

node.js中使用SQL Server可以通过第三方包:mssql,类似node.js连接mysql的包mysql一样,我项目中涉及分库分表存储数据,下面我将我项目中主要代码粘贴如下可供参考:

配置默认数据库:默认数据库用来查询项目基础数据,文件命名为:mssqldefaultconfig.js

// 默认数据库配置:
// 引入前先: npm i mssql 下载依赖包
const mssql = require('mssql')
// 默认数据库配置:
const option = 
  // sql server数据库所在服务器:
  server: '***.**.***.***', 
  // sql server数据库监听的端口号,默认1433:
  port: ****,
  // sql server数据库某个数据库名称:
  database: '********2021',
  // 用户名:
  user: '******',
  // 密码:
  password: '*********',
  options: 
    encrypt: false,  //加密
    enableArithAbort: false
  ,
  pool: 
    min: 0,
    max: 10,
    idleTimeoutMillis: 3000
  


// 创建默认数据库连接池:
const pool = new mssql.ConnectionPool(option)
pool.on('error', err => 
  console.log('数据库连接错误: ', err)
)
// 连接数据库:
const connection = pool.connect()

// 封装一个执行sql语句的方法,用来操作数据库:
const defaultDataBaseQuery = async (sql, callBack) =>   
  const ps = new mssql.PreparedStatement(await connection)
  ps.prepare(sql, err =>   
    if (err)  
      console.log('prepare错误:' + err)
      return
      
    ps.execute('', (err, result) =>   
      if (err)  
        console.log('execute错误:' + err)
        return
        
      ps.unprepare(err =>   
        if (err)  
          console.log('unprepare错误:' + err)
          callBack(err, null)
          return
          
        callBack(err, result)
      )
    )
  )


// 导出默认数据库:
module.exports = defaultDataBaseQuery

配置动态数据库 :动态数据库是指按规定的日期自动切换到某个数据,文件命名为:mssqlswitchconfig.js

// 动态库配置:
const mssql = require('mssql')
// 定时事务:一个第三方的包,类似定时器,可以设置某段代码多久执行一次(某个日期点执行某段代码)
const schedule = require('node-schedule')
// 引入默认数据库配置:动态库切换也是需要借助基础库的,因此需要引入基础库:
const defaultDataBaseQuery = require('./mssqldefaultconfig')

// 导出一个动态的数据库配置:按年份配置数据库
function createSqlServeOption() 
  let date = new Date()
  let yearstr = date.getFullYear()
  // 动态数据库配置:
  let optionObj = 
    server: '***.**.***.***', 
    port: ****,
    // 动态库命名最方便的就是前缀固定+后缀年份等
    database: '******' + yearstr,
    user: '*****',
    password: '************',
    options: 
      encrypt: false,  //加密
      enableArithAbort: false
    ,
    pool: 
      min: 0,
      max: 10,
      idleTimeoutMillis: 3000
    
  
  return optionObj


// 程序启动配置当前年份动态库option:
let option = createSqlServeOption()
// 数据库连接变量
let pool;

// 程序启动连接当前年份动态库:
pool = new mssql.ConnectionPool(option)

// 每年1月1日自动切换到最新数据库:
schedule.scheduleJob('0 0 0 1 1 *', function () 
  const date = new Date()
  const yearstr = date.getFullYear()
  let dbStr = '******' + yearstr
  // 降低频率切换:因为此项目为老项目二开,数据库中数据和数据结构都是不动的,只提供使用权,这里动态创建新的数据库业务不在我项目,所以我无法创建数据库且不确定新的数据库是否已经创建好,因此只能不断的查询新的数据库是否存在,如果存在立马切换到新的数据库,否则持续每次降低频率的尝试查询数据库是否存在
  let count = 0
  // 如果新的一年数据库创建了那么立马切换到新创建的数据库,否则延迟递归切换
  function switchDB () 
    // SQL Server中无法使用:'SELECT table_name FROM `INFORMATION_SCHEMA`.`TABLES` WHERE table_schema = ******'+yearstr此sql语句查询某个数据库中是否有某表,只能通过下面数据查询到所有数据库,然后去判断数据库中是否有新的数据库名称
    let sql = 'select * From master.dbo.sysdatabases'
    defaultDataBaseQuery(sql,async (error,result) => 
      try 
        if (error) 
          throw error
         else 
          const isExist = result.recordset.find(item => item.name == dbStr) // 不存在是返回undefined
          if (isExist) 
            option.database = dbStr
            // 动态切换新的数据库连接:如果将new mssql.ConnectionPool(option)提到最外面,这里我不能保证它会重新创建新连接,为了确保期间,我在这里重新创建一次
            pool = new mssql.ConnectionPool(option)
            // 存在的情况下return掉,否则继续延迟尝试切换:
            return
           else 
            // 延迟重新判断是否存在数据库
            setTimeout(() => 
              count++
              switchDB()
            ,1000 * count)
          
        
       catch (err) 
        console.log('查询新创建数据库是否存在失败' + err)
      
    )
  
  switchDB()
)

// 连接池创建错误时:
pool.on('error', err => 
  console.log('数据库连接错误: ', err)
)

// 创建数据库连接:
const connection = pool.connect()

// 动态库查询方法:
const switchDataBaseQuery = async (sql, callBack) =>   
  const ps = new mssql.PreparedStatement(await connection)
  ps.prepare(sql, err =>   
    if (err)  
      console.log('prepare错误:' + err)
      return
      
    ps.execute('', (err, result) =>   
      if (err)  
        console.log('execute错误:' + err)
        return
        
      ps.unprepare(err =>   
        if (err)  
          console.log('unprepare错误:' + err)
          callBack(err, null)
          return
          
        callBack(err, result)
      )
    )
  )


// 导出动态数据库:
module.exports = switchDataBaseQuery 

查询页api接口路由文件

// 记录查询页:

// 引入日期格式化函数:
const dataFormat = require('../utils/utils')
// 引入路由模块:
const Router = require('koa-router')
// 引入默认数据库配置
const defaultDataBaseQuery = require('../config/mssqldefaultconfig')
// 引入动态数据库配置
const switchDataBaseQuery = require('../config/mssqlswitchconfig')
// 引入redis配置文件:
const redisClient = require('../config/redisconfig')
// 创建路由实例:
const router = new Router(prefix:'/api')//里面可接收一个对象,可以设置些默认配置,如prefix:'/api'设置路由匹配前缀

// 在创建路由时默认加了前缀 /api ,下面router.post('/login', ()=>)可直接匹配:'/api/login'路由

// 查实时值接口:
router.post('/getrealtime',async (ctx, next) => 
  let id, ParaId = ctx.request.body
  // 设备单位等参数redis缓存key
  let keys = 'equipmentunit' + ParaId
  return new Promise((resolve,reject) => 
    // 查仪表相关配置参数:
    function queryEquipOption() 
      // 判断是否存在key:存在走缓存,否则走数据库:
      return new Promise((resolve,reject) => 
        redisClient.exists(keys, (err, res) => 
          if (res == 0) 
            let sql1 = 'SELECT Name,Unit,Xh FROM Equipment_Para_Two WHERE FId= '+ParaId +' AND WeiXin=1'
            defaultDataBaseQuery(sql1, (error, result) => 
              if (error) 
                ctx.body = cod: 201, msg: '查询错误!'
                console.log('查询实时值sql1错误:' + error)
                reject()
               else 
                if (result.recordset.length === 0) 
                  ctx.body = cod: 200, msg: '无实时值!', resultList: [], time: dataFormat()
                  resolve()
                  return
                
                // 将查询到的数据存到redis中600秒过期:
                redisClient.setex(keys, 60 * 10, JSON.stringify(result))
                resolve(result)
              
            )
           else 
            redisClient.get(keys, (error,res) => 
              resolve(JSON.parse(res))
            )
          
        )
      )
    
    // 查实时值数据:
    async function queryTimeData() 
      const option = await queryEquipOption()
      // 要获取的通道
      const dnArray = [...new Set(option.recordset.map(it => 'D' + it.Xh))]
      // 要查询的通道值字段:
      const dnStr = dnArray.toString()
      // 查询时刻值:
      let sql2 = 'SELECT TOP 1 '+dnStr+', SubTime FROM Equipment_Data WHERE EqId = '+id+' order by id desc'
      switchDataBaseQuery(sql2, (error, result) => 
        if (error) 
          ctx.body = cod: 201, msg: '查询错误!'
          console.log('查询实时值sql2错误:' + error)
         else 
          if (result.recordset.length === 0) 
            ctx.body = cod: 200, msg: '无实时值!', resultList: [], time: dataFormat()
            resolve()
            return
          
          // 实时值数组
          let resultArray = []
          option.recordset.forEach(item => 
            resultArray.push(...item,...value: result.recordset[0]['D' + item['Xh']])
          )
          ctx.body = cod: 200, msg: '请求实时值数据成功!', resultList: resultArray, time: dataFormat(result.recordset[0].SubTime)
          resolve()
        
      )
    
    queryTimeData()
  )
)

// 查历史值接口:
router.post('/gethistory', async (ctx, next) => 
  const date1, date2, ParaId, id, page = ctx.request.body
  const startYear = date1.slice(0,4)
  const endYear = date2.slice(0,4)
  if (startYear !== endYear) 
    ctx.body = cod: 200, msg: '日期不能跨年!', resultList: []
    return
  
  // 设备单位等参数redis缓存key
  let keys = 'equipmentunit' + ParaId
  return new Promise((resolve, reject) => 
     // 查仪表相关配置参数:
     function queryEquipOption() 
      // 判断是否存在key:存在走缓存,否则走数据库:
      return new Promise((resolve,reject) => 
        redisClient.exists(keys, (err, res) => 
          if (res == 0) 
            let sql1 = 'SELECT Name,Unit,Xh FROM Equipment_Para_Two WHERE FId= '+ParaId +' AND WeiXin=1'
            defaultDataBaseQuery(sql1, (error, result) => 
              if (error) 
                ctx.body = cod: 201, msg: '查询错误!'
                console.log('查询实时值sql1错误:' + error)
                reject()
               else 
                if (result.recordset.length === 0) 
                  ctx.body = cod: 200, msg: '无实时值!', resultList: []
                  resolve()
                  return
                
                // 将查询到的数据存到redis中600秒过期:
                redisClient.setex(keys, 60 * 10, JSON.stringify(result))
                resolve(result)
              
            )
           else 
            redisClient.get(keys, (error,res) => 
              resolve(JSON.parse(res))
            )
          
        )
      )
    
    // 查历史值数据:
    async function queryHistoryData() 
      const option = await queryEquipOption()
      // 要获取的通道
      const dnArray = [...new Set(option.recordset.map(it => 'D' + it.Xh)《Pro SQL Server Internals》翻译之索引

《Pro SQL Server Internals》之Data Pages Data Rows

SQL Server两种分页性能比较

SQL Server 分页

SQL Server 内存使用情况

SQL Server 分页查询存储过程