精华内容
下载资源
问答
  • 诚然,一般的数据差异,比如是一行的内容不同,市场上有比较成熟的 compare2 等对比工具。但是如果是对比数据的一列是否相同,这就会变得比较麻烦。v1.0 纯人工对比我们在做一些数据迁移等功能时,经常需要...

    对比数据的痛苦

    不知道你是否也像我一样,在快乐编写代码的时候,必须进行一些数据库的数据对比工作。

    诚然,一般的数据差异,比如是每一行的内容不同,市场上有比较成熟的 compare2 等对比工具。

    但是如果是对比数据的每一列是否相同,这个就会变得比较麻烦。

    c8b1bfb8d01de060b3bf8ebd06a82a7c.png

    v1.0 纯人工对比

    我们在做一些数据迁移等功能时,经常需要对比数据是否正确,最常见的方法就是人工一列一列的对比。

    一开始老马也是这么和同事对的,对了几天之后感觉效率实在是低,而且还容易看花眼。

    于是我就是琢磨,这个东西用程序对比应该会简单很多。

    v2.0 半人工对比

    说干就干,我花半天时间实现了一个基于 jsqlparser 可以解析类似于 insert into xxx (xx, xx, xx) values (xx, xx, xx); 的工具类。

    然后对比 2 边的数据,这下对于一张表上百个字段的对比,一些变得快了许多,准确率也高了很多。

    不要问我为什么会有上百个字段,这都是历史沉淀下来的瑰宝。。。

    ps: insert into 语句是否通过数据库连接工具手工导出的。

    后来又发现另一个问题:表太多,如果想换一个数据对比,我手工导出一遍又要花费数十分钟的时间,关键是重复且枯燥。

    e07fcc66f3eb955fcf2955e8c2c9a111.png

    既然重复,那么可以使用程序实现吗?

    v3.0 对比基本自动化

    于是我下班后熬夜实现了这个版本: java 程序实现了数据的导出持久化,然后进行修改前后的差异对比。

    下面我分享一下自己的思路,以及核心源码,文末有下载福利。

    希望对你工作和学习提供帮助。

    整体理念

    我希望这个工具是 MVP 的理念,由简单到复杂,后期逐渐丰富特性。

    要有可拓展性,目前支持 mysql/oracle/sql server 等主流数据库,用户可以定制化开发。

    尽可能少的依赖,使用原生的 jdbc,不需要引入 mybatis 等框架。

    核心依赖

    下面列举一下我用到的核心依赖:

    fastjson 用于数据持久化为 json

    mysql-connector-java 数据库连接驱动

    jsqlparser 辅助工具,解析 sql 使用,非必须

    实现思路根据指定的 jdbc 连接信息,自动选择对应的 jdbc 实现。

    执行对应的 sql,将结果解析为 map,进行 JSON 持久化

    对持久化的 json 进行差异对比,展现出差异结果

    有了这个思路,一切就会变得朴实无华。

    当然在此之前,需要我们把代码实现出来,下面进入写BUG环节:

    af35aeb73a8d88ce289bf682e744905b.png

    jdbc 实现

    核心接口

    考虑到后期不同数据库实现,我们统一定义一个查询接口/**

    * JDBC 访问层

    * @author 老马啸西风

    * @date 2017/8/1

    */

    public interface JdbcMapper {

    /**

    * 执行查询语句

    * @param querySql

    * @return

    */

    ResultSet query(String querySql);

    }

    抽象实现

    这里提供了基本的抽象实现。

    子类只需要实现对应的连接获取信息即可。public abstract class AbstractJdbcMapper implements JdbcMapper {

    protected JdbcVo jdbcVo;

    public AbstractJdbcMapper(JdbcVo jdbcVo) {

    this.jdbcVo = jdbcVo;

    }

    /**

    * 获取数据库连接

    * @return

    */

    protected abstract Connection getConnection();

    @Override

    public ResultSet query(String querySql) {

    ResultSet rs = null;

    Connection connection = getConnection();

    try {

    Statement stmt = null;

    stmt = connection.createStatement();

    rs = stmt.executeQuery(querySql);

    } catch (Exception e) {

    System.out.println("SQL: " + querySql);

    throw new ExportdbException(e);

    }

    return rs;

    }

    }

    JdbcVo 连接信息

    这个对象主要是数据库连接信息对象:public class JdbcVo {

    /**

    * 驱动类名称

    */

    private String driverClassName;

    /**

    * 数据库链接

    */

    private String url;

    /**

    * 用户名称

    */

    private String username;

    /**

    * 密码

    */

    private String password;

    //getter & setter

    }

    mysql 实现

    此处以 mysql 为例:import com.github.houbb.exportdb.dto.JdbcVo;

    import java.sql.Connection;

    import java.sql.DriverManager;

    import java.sql.SQLException;

    /**

    * mysql 实现

    * @author 老马啸西风

    * @date 2017/8/1

    */

    public class MySqlJdbcMapper extends AbstractJdbcMapper {

    public MySqlJdbcMapper(JdbcVo jdbcVo) {

    super(jdbcVo);

    }

    @Override

    protected Connection getConnection() {

    try {

    Class.forName(jdbcVo.getDriverClassName());

    return DriverManager.getConnection(jdbcVo.getUrl(),

    jdbcVo.getUsername(),

    jdbcVo.getPassword());

    } catch (ClassNotFoundException | SQLException e) {

    e.printStackTrace();

    }

    return null;

    }

    }

    这里主要是对连接的初始化,连接不同的数据库,都需要引入对应的数据源。

    行数据导出实现

    下面是导出的核心实现:

    接口定义public interface IExportdb {

    /**

    * 查询

    * @param context 上下文

    * @param sql sql

    * @return 结果

    * @since 0.0.1

    */

    QueryResultVo query(final ExportdbContext context, final String sql);

    }

    这里指定了需要执行的 sql。

    context 中为了便于后期拓展,目前只有 JdbcMapper。

    返回的就是 QueryResultVo,就是查询结果,定义如下:public class QueryResultVo {

    /**

    * 表名称

    */

    private String tableName;

    /**

    * 数据库名称

    *

    * @since 0.0.2

    */

    private String databaseName;

    /**

    * 结果集合

    */

    private List> resultMaps;

    /**

    * 执行的 sql

    */

    private String sql;

    //getter & setter

    }

    默认实现

    默认的导出实现如下:import com.github.houbb.exportdb.core.ExportdbContext;

    import com.github.houbb.exportdb.core.IExportdb;

    import com.github.houbb.exportdb.dal.JdbcMapper;

    import com.github.houbb.exportdb.dto.QueryResultVo;

    import com.github.houbb.exportdb.exception.ExportdbException;

    import com.github.houbb.heaven.util.lang.StringUtil;

    import net.sf.jsqlparser.JSQLParserException;

    import net.sf.jsqlparser.parser.CCJSqlParserUtil;

    import net.sf.jsqlparser.statement.Statement;

    import net.sf.jsqlparser.statement.insert.Insert;

    import net.sf.jsqlparser.statement.select.PlainSelect;

    import net.sf.jsqlparser.statement.select.Select;

    import java.sql.ResultSet;

    import java.sql.ResultSetMetaData;

    import java.sql.SQLException;

    import java.util.ArrayList;

    import java.util.LinkedHashMap;

    import java.util.List;

    import java.util.Map;

    /**

    * @author binbin.hou

    * @since 0.0.1

    */

    public class Exportdb implements IExportdb {

    @Override

    public QueryResultVo query(ExportdbContext context, String sql) {

    try {

    final JdbcMapper jdbcMapper = context.jdbcMapper();

    ResultSet resultSet = jdbcMapper.query(sql);

    List> maps = new ArrayList<>();

    String tableName = null;

    while (resultSet.next()) {

    final ResultSetMetaData metaData = resultSet.getMetaData();

    // 设置表名称

    if(tableName == null) {

    tableName = metaData.getTableName(1);

    }

    Map map = new LinkedHashMap<>();

    // 为空直接返回,大于1则报错

    // 列数的总数

    int columnCount = metaData.getColumnCount();

    for (int i = 1; i <= columnCount; i++) {

    String columnName = metaData.getColumnName(i);

    Object value = resultSet.getObject(columnName);

    map.put(columnName, value);

    }

    maps.add(map);

    }

    if(StringUtil.isEmptyTrim(tableName)) {

    Statement statement = CCJSqlParserUtil.parse(sql);

    Select select = (Select)statement;

    PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

    tableName = plainSelect.getFromItem().toString();

    }

    return QueryResultVo.newInstance().tableName(tableName)

    .databaseName("")

    .sql(sql)

    .resultMaps(maps);

    } catch (SQLException | JSQLParserException throwables) {

    throw new ExportdbException(throwables);

    }

    }

    }

    其实实现非常简单,我们主要讲一下两点:

    (1)表名称

    mysql 经测试可以通过如下方式获取:resultSet.getMetaData();

    tableName = metaData.getTableName(1);

    oracle 我在测试的时候,发现无法获取。所以是借助 sqlparser 解析我们的查询语句得到的。

    暂时主要是支持查询,所以这里写的有些固定了,后续可以优化一下。if(StringUtil.isEmptyTrim(tableName)) {

    Statement statement = CCJSqlParserUtil.parse(sql);

    Select select = (Select)statement;

    PlainSelect plainSelect = (PlainSelect) select.getSelectBody();

    tableName = plainSelect.getFromItem().toString();

    }

    (2)列信息

    每一个查询,可能都对应多条记录。

    我们看一下每一条记录的构建:while (resultSet.next()) {

    final ResultSetMetaData metaData = resultSet.getMetaData();

    Map map = new LinkedHashMap<>();

    // 为空直接返回,大于1则报错

    // 列数的总数

    int columnCount = metaData.getColumnCount();

    for (int i = 1; i <= columnCount; i++) {

    String columnName = metaData.getColumnName(i);

    Object value = resultSet.getObject(columnName);

    map.put(columnName, value);

    }

    maps.add(map);

    }

    这个经常写 jdbc 的小伙伴也一定不陌生。

    你说现在都用 mybatis 了,谁还写 jdbc 啊,这么 low。

    那么,你自己手写一个 mybatis,这些也是必会的。

    差异对比

    导出的使用

    我们可以把一行数据导出,可以在修改前后分别导出。

    如果是导出到不同的库,不同的表,那么就进行不同库表之间的导出。

    导出结果之后,就需要进行对比了。

    对比实现

    接口定义

    对于导出结果的处理,你可以根据自己的实际情况自行选择。

    比如导出为 csv/json/insert 等,对比差异也可以按照自己的需求定制。public interface IQueryResultHandler {

    /**

    * 结果处理类

    * @param queryResultVo 查询结果

    */

    void handler(final QueryResultVo queryResultVo);

    }

    持久化

    此处介绍一种比较简单实用的方式:json 持久化。import com.alibaba.fastjson.JSON;

    import com.alibaba.fastjson.serializer.SerializerFeature;

    import com.github.houbb.exportdb.dto.QueryResultVo;

    import com.github.houbb.exportdb.support.result.IQueryResultHandler;

    import com.github.houbb.heaven.util.io.FileUtil;

    import java.util.ArrayList;

    import java.util.List;

    import java.util.Map;

    /**

    * @author 老马啸西风

    * @since 0.0.1

    */

    public class FileJsonQueryResultHandler implements IQueryResultHandler {

    /**

    * 默认的文件输出路径

    *

    * 根据操作系统,自动设置

    * @since 0.0.1

    */

    private final String dir;

    public FileJsonQueryResultHandler(String dir) {

    this.dir = dir;

    }

    public FileJsonQueryResultHandler() {

    this("D:\\exportdb\\");

    }

    /**

    * 结果处理类

    *

    * @param queryResultVo 查询结果

    */

    @Override

    public void handler(final QueryResultVo queryResultVo) {

    String path = dir+queryResultVo.tableName()+".edb";

    System.out.println("文件路径: " + path);

    List> list = queryResultVo.resultMaps();

    List lines = new ArrayList<>(list.size()+1);

    lines.add("-- "+queryResultVo.sql());

    for(Map map : list) {

    lines.add(JSON.toJSONString(map, SerializerFeature.WriteMapNullValue));

    }

    FileUtil.write(path, lines);

    }

    }

    我们将行数据持久化到文件中,注意这里指定了 JSON.toJSONString(map, SerializerFeature.WriteMapNullValue);

    这样可以让 null 字段也输出,更加方便对比。

    文件差异对比实现

    上面我们假设将文件输出到 2 个文件,下面指定文件路径就可以进行对比了:/**

    * 差异对比

    * @param oldPath 原始路径

    * @param newPath 新的路径

    */

    public static void differ(final String oldPath, final String newPath) {

    List oldLines = FileUtil.readAllLines(oldPath);

    List newLines = FileUtil.readAllLines(newPath);

    System.out.println(FileUtil.getFileName(oldPath)+" 对比开始---------------");

    for(int i = 0; i < oldLines.size(); i++) {

    String oldL = oldLines.get(i);

    String newL = newLines.get(i);

    if(oldL.startsWith("--")) {

    continue;

    }

    System.out.println("第 " + (i+1) +" 行对比: ");

    differMaps(oldL, newL);

    }

    System.out.println(FileUtil.getFileName(oldPath)+" 对比结束---------------");

    System.out.println();

    }

    private static void differMaps(final String oldMap, final String newMap) {

    Map om = JSON.parseObject(oldMap);

    Map nm = JSON.parseObject(newMap);

    for(Map.Entry entry : om.entrySet()) {

    String key = entry.getKey();

    Object oldV = om.get(key);

    Object newV = nm.get(key);

    // 跳过 null 的对比

    if(oldV == null && newV == null) {

    continue;

    }

    if(!ObjectUtil.isEquals(oldV, newV)) {

    System.out.println("差异列:" + key +", 旧值:" + oldV + ", 新值:" + newV);

    }

    }

    }

    这里将差异内容,直接 console 控台输出。

    文件夹

    当然,我们也可以对比两个文件夹下的内容。

    实现如下:public static void differDir(final String oldDir, final String newDir) {

    File[] oldFiles = new File(oldDir).listFiles();

    for(File file : oldFiles) {

    String fileName = file.getName();

    String aop = file.getAbsolutePath();

    String anp = newDir+fileName;

    differ(aop, anp);

    }

    }

    引导类

    便利性

    上面我们把核心实现都搞定了,但是用户使用起来还是不够方便。因为配置等不够优雅。

    所以我们引入引导类,帮助用户快速使用:/**

    * @author 老马啸西风

    * @since 0.0.1

    */

    public class ExportdbBs {

    private ExportdbBs(){}

    /**

    * 导出实现

    * @since 0.0.1

    */

    private final IExportdb exportdb = new Exportdb();

    /**

    * 驱动类名称

    */

    private String driverName = DriverNameConstant.MYSQL;

    /**

    * 数据库链接

    */

    private String url = "jdbc:mysql://localhost:3306/test";

    /**

    * 用户名称

    */

    private String username = "root";

    /**

    * 密码

    */

    private String password = "123456";

    public static ExportdbBs newInstance() {

    return new ExportdbBs();

    }

    public ExportdbBs driverName(String driverName) {

    this.driverName = driverName;

    return this;

    }

    public ExportdbBs url(String url) {

    this.url = url;

    return this;

    }

    public ExportdbBs username(String username) {

    this.username = username;

    return this;

    }

    public ExportdbBs password(String password) {

    this.password = password;

    return this;

    }

    /**

    * 查询

    * @param sql sql

    * @return 结果

    * @since 0.0.1

    */

    public QueryResultVo query(final String sql) {

    //1. 构建 vo

    JdbcVo jdbcVo = new JdbcVo(driverName, url, username, password);

    //2. 获取 mapper

    final JdbcMapper jdbcMapper = getJdbcMapper(jdbcVo);

    //3. 构建上下文

    final ExportdbContext context = ExportdbContext.newInstance().jdbcMapper(jdbcMapper);

    return this.exportdb.query(context, sql);

    }

    /**

    * 查询并且处理

    * @param queryResultHandler 查询结果处理器

    * @param sql sql

    * @since 0.0.1

    */

    public void queryAndHandle(final IQueryResultHandler queryResultHandler,

    final String sql, final String... otherSqls) {

    QueryResultVo queryResultVo = this.query(sql);

    queryResultHandler.handler(queryResultVo);

    // 同理处理其他的 sql

    for(String os : otherSqls) {

    QueryResultVo vo = this.query(os);

    queryResultHandler.handler(vo);

    }

    }

    /**

    * 查询并且处理

    * @param queryResultHandler 查询结果处理器

    * @param sqlList sql 列表

    * @since 0.0.2

    */

    public void queryAndHandle(final IQueryResultHandler queryResultHandler,

    List sqlList) {

    // 同理处理其他的 sql

    for(String sql : sqlList) {

    System.out.println("开始执行:" + sql);

    QueryResultVo vo = this.query(sql);

    queryResultHandler.handler(vo);

    }

    }

    private JdbcMapper getJdbcMapper(JdbcVo jdbcVo) {

    if(DriverNameConstant.MYSQL.equalsIgnoreCase(driverName)) {

    return new MySqlJdbcMapper(jdbcVo);

    }

    if(DriverNameConstant.ORACLE.equalsIgnoreCase(driverName)) {

    return new OracleJdbcMapper(jdbcVo);

    }

    if(DriverNameConstant.SQL_SERVER.equalsIgnoreCase(driverName)) {

    return new SqlServerJdbcMapper(jdbcVo);

    }

    throw new UnsupportedOperationException();

    }

    }

    这里为用户提供了 mysql 最基本的配置,以及常用的查询处理方法。

    测试

    下面我们来看一下测试的效果:

    直接查询QueryResultVo resultVo = ExportdbBs.newInstance().query("select * from user;");

    System.out.println(resultVo);

    查询并处理final String sql = "select * from user;";

    final IQueryResultHandler handler = new FileJsonQueryResultHandler();

    ExportdbBs.newInstance().queryAndHandle(handler, sql);

    两次导出可以指定文件路径,比如分别是:

    D:\exportdb\old\ 和 D:\exportdb\new\

    针对两次结果对比final String oldP = "D:\\exportdb\\old\\";

    final String newP = "D:\\exportdb\\new\\";

    CompareUtil.differDir(oldP, newP);

    差异结果就会被输出到控台。

    4853fbbc223c5c883fb735ca480bf7b3.png

    一切顺利,不过革命尚未成功,同学仍需加班呀~~~

    不足之处

    这是一个 v0.0.1 版本,还有很多不足。

    比如:导出为 csv

    导出为 insert/update 语句

    导出的文件名称自定义策略

    可以指定多个 sql 是否生成在同一个文件中

    导出路径根据操作系统,自动变更

    更加便于使用,比如页面指定数据源+sql,页面显示对应差异结果。

    不过也基本可用,符合我们最初的设想。

    小结

    不知道你平时又是如何对比数据的呢?

    如果你需要这个工具,可以关注【老马啸西风】,后台回复【对比】即可。

    希望本文对你有帮助,如果有其他想法的话,也可以评论区和大家分享哦。

    各位极客的点赞收藏转发,是老马持续写作的最大动力!

    80d4941b3e7050e22b4b03b5def69ac1.png

    展开全文
  • 在MySQL运维中,研发同事想对比下两不同实例上的数据并找出差异,除主键外还需要对比字段,如何做呢?第一种方案,写程序将两实例上的一行数据取出来进行对比,理论可行,但是对比时间较长。第二种方案...

    在MySQL运维中,研发同事想对比下两个不同实例上的数据并找出差异,除主键外还需要对比每一个字段,如何做呢?

    第一种方案,写程序将两个实例上的每一行数据取出来进行对比,理论可行,但是对比时间较长。

    第二种方案,对每一行数据所有字段合并起来,取checksum值,再按照checksum值对比,看着可行,尝试下。

    首先要合并所有字段的值,选用MySQL提供的CONCAT函数,如果CONCAT函数中包含NULL值,会导致最终结果为NULL,因此需要使用IFNULL函数来替换NULL值,如:

    CONCAT(IFNULL(C1,''),IFNULL(C2,''))

    加入表有很多行,手动拼个脚本比较累,别急,可以使用information_schema.COLUMNS来处理:

    ## 获取列名的拼接串

    SELECT

    GROUP_CONCAT('IFNULL(',COLUMN_NAME,','''')')

    FROM information_schema.COLUMNS

    WHERE TABLE_NAME='table_name';

    假设我们有测试表:

    CREATE TABLEt_test01

    (

    idINT AUTO_INCREMENT PRIMARY KEY,

    C1INT,

    C2INT)

    我们便可以拼接出下面的SQL:

    SELECTid,

    MD5(CONCAT(

    IFNULL(id,''),

    IFNULL(c1,''),

    IFNULL(c2,''),

    ))ASmd5_valueFROM t_test01

    在两个实例上执行下,然后把结果使用beyond compare对比下,就很容易找出不相同的行以及主键ID

    对于数据量较大的表,执行出来的结果集也很大,对比起来比较费劲,那就先尝试缩小结果集,可以将多行记录的md5值合并起来求MD5值,如果最后MD5值相同,则这些行相同,如果不同,则证明存在差异,再按照这些行进行逐行对比。

    假设我们按照1000行一组来进行对比,如果需要将分组后的结果合并,需要使用GROUP_CONCAT函数,注意在GROUP_CONCAT函数中添加排序保证合并数据的顺序, SQL如下:

    SELECT

    min(id) asmin_id,max(id) asmax_id,count(1) asrow_count,

    MD5(GROUP_CONCAT(

    MD5(CONCAT(

    IFNULL(id,''),

    IFNULL(c1,''),

    IFNULL(c2,''),

    ))ORDER BYid

    ))ASmd5_valueFROMt_test01GROUP BY (id div 1000)

    执行结果为:

    min_id max_id row_count md5_value0 999 10007d49def23611f610849ef559677fec0c1000 1999 100095d61931aa5d3b48f1e38b3550daee082000 2999 1000b02612548fae8a4455418365b3ae611a3000 3999 1000 fe798602ab9dd1c69b36a0da568b6dbb

    当差异数据较少时,即使需要对比上千万数据,我们可以轻松根据根据min_id和max_id来快速定位到哪1000条数据里存在差异,再进行逐行MD5值对比,最终找到差异行。

    最终对比图:

    4f9b7bbb0c23cd92245b5690e19690b0.png

    ##=====================================================================##

    PS:

    在使用GROUP_CONCAT时,需要配置MySQL变量group_concat_max_len,默认值为1024,超出部分会被阶段。

    参考链接:https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html

    0b1331709591d260c1c78e86d0c51c18.png

    展开全文
  • 下面简单阐述下各个版本新增的功能: SQL SERVER 2000 日志传送 索引视图 SQL SERVER 2005 分区 数据库镜像 (只有 SQL Server 2005 Enterprise Edition SP1 和更高版本支持异步数据库镜像。) 联机索引 数据库快照 ...

    SQLSERVER各版本功能对比

    从我最开始接触的SQL SERVER 2000 开始,已经经历了如此多的版本。下面简单阐述下各个版本新增的功能:

    SQL SERVER 2000
    日志传送
    索引视图

    SQL SERVER 2005
    分区

    数据库镜像
    (只有 SQL Server 2005 Enterprise Edition SP1 和更高版本支持异步数据库镜像。)
    联机索引
    数据库快照
    复制
    故障转移群集

    SQL SERVER 2008

    数据压缩
    资源调控器
    备份压缩

    SQL SERVER 2008 R2

    R2标志表示这是SQL Server的一个中间版本,而不是一个主版本 .此版本目前我的客户中,使用还是非常多,性能稳定,虽然新增功能比较少:
    新增数据中心版,最大支持256核.
    Unicode压缩

    (为Unicode存储提供一个简单的压缩方案,通过Unicode压缩,可以减少Unicode字符对空间的占用)

    SQL SERVER 2012

    AlwaysOn
    Columnstore 索引
    增强的审计功能
    大数据支持

    SQL SERVER 2014
    这个版本的新特效特别多,和非常有用,可以多了解下.

    内存优化表
    备份加密
    针对基数估计的新设计
    AlwaysOn 增强功能
    延迟持续性 (将部分或所有事务指定为延迟持久事务,从而能够缩短延迟)
    分区切换和索引生成

    (官网写得Partition Switching and Indexing,感觉是有问题的,其实就是分区表的单个分区可以重建)
    列存储索引
    缓冲池扩展 就是使用SSD 扩展缓冲池
    增量统计信息
    资源调控器增强功能
    (–之前只能控制CPU和内存,2014 开始可以控制IO)

    DBCC CHECK 支持maxdop 提示

    SQL SERVER 2016

    全程加密技术(Always Encrypted)
    JSON支持
    多TempDB数据库文件

    (以前也是支持的,在2014 开始就在error log提示,2016中,在安装时就可以设置。)
    Query Store
    (前几天去参加微软的培训还讲到的,挺不错的功能。可以帮助解决参数嗅探的问题,数据库升级的时候也可以用到它)
    支持R语言
    Live Quer y St at ist ics
    (可以更清晰的看到执行计划的开销(水流式))

    SQL SERVER 2017
    可恢复的在线索引重建

    允许您在发生故障(例如故障切换到副本或磁盘空间不足)之后恢复在线索引重建操作。

    IDENTITY_CACHE option

    当此选项设置为OFF时,它可以避免在服务器意外重新启动或故障切换到辅助服务器的情况下,标识列值的间隙

    CLR在.NET Framework中使用代码访问安全性(CAS),该框架不再支持安全边界。

    使用PERMISSION_SET = SAFE创建的CLR程序集可能能够访问外部系统资源,调用非托管代码并获取sysadmin权限

    图表数据库功能

    用于多对多关系建模

    Read-scale availability groups without cluster

    可以在不依赖集群的情况下,搭建读的可用性组,分担读压力。不过此时不能实现高可用。

    R/PYTHON 机器学习方面的功能

    展开全文
  • 获取单个表的行数使用...执行结果获取两个表的行数使用union组合每个select查询的结果集例如,要在单个查询中获取customers和orders表的行数SELECT'customers' tablename,COUNT(1) rowsFROMcustomersUNIONSELECT'o...

    获取单个表的行数

    使用count(*)或者count(1)

    SELECT

    count(1) AS count

    FROM

    table_name;

    执行结果

    获取两个表的行数

    使用union组合每个select查询的结果集

    例如,要在单个查询中获取customers和orders表的行数

    SELECT

    'customers' tablename,

    COUNT(1) rows

    FROM

    customers

    UNION

    SELECT

    'orders' tablename,

    COUNT(1) rows

    FROM

    orders;

    运行结果

    获取数据库中所有表的行数

    SELECT

    table_name,

    table_rows

    FROM

    information_schema.tables

    WHERE

    table_schema = 'dbname'

    ORDER BY table_rows desc;

    运行结果

    【2017-06-29】在登录页面自动返回上次请求页面、Js获取table中的行数与列数

    一.在登录页面自动返回上次请求页面 Request.UrlReferrer比如 if (Request.UrlReferrer != null) { //如果能获取来路地址 Response.Redi ...

    Mysql误删表中数据与误删表的恢复方法

    由于头两天面试时被问了这样一个问题,如果某同事误删了某个表,你该怎么恢复? 当时想了一下,因为博主没有遇到过这个问题,但是也多少了解一些,所以就回答通过mysql的binlog日志进行恢复. 面试官当 ...

    mysql -- 清空表中数据

    删除表信息的方式有两种 :truncate table table_name;delete * from table_name;注 : truncate操作中的table可以省略,delete操作中的 ...

    mysql获取表中日期的年月日时分秒

    SELECT year(callTheRollTime) from schedule_account 获取年 SELECT month(callTheRollTime) from schedule_a ...

    mssqlserver获取表说明和行数

    SELECT a.*,t.rows FROM ( ) ) AS a left join (, )) ) AS t ON a.表名=t.name

    c&num;中动态创建textbox并且从数据库中获取表中数据添加到textbox中

    private void FormLugOther_Load(object sender, EventArgs e) { foreach (string str in FormLug.FieldLis ...

    Navicat使用教程:获取MySQL中的行数(第1部分)

    下载Navicat Premium最新版本 Navicat Premium是一个可连接多种数据库的管理工具,它可以让你以单一程序同时连接到MySQL.Oracle及PostgreSQL数据库,让管理不 ...

    获取apache ignite缓存中的数据行数少于实际行数

    我将ignite项目打包放到linux下,在linux下获取window中存放在oracle数据库中的数据,linux服务器作为ignite的服务端节点,我在本地启动tomact,作为ignite客户 ...

    查询执行成本高(查询访问表数据行数多)而导致实例 CPU 使用率高是 MySQL 非常常见的问题

    MySQL CPU 使用率高的原因和解决方法_产品性能_常见问题_云数据库 RDS 版-阿里云 https://help.aliyun.com/knowledge_detail/51587.html ...

    随机推荐

    C语言混乱代码大赛

    main() {printf(&unix["\021%six\012\0"], (unix)["have"] + "fun" - 0 ...

    ffrpc相关文章列表

    ffrpc 是异步c++通信库.可以说是传统rpc模式和zeromq模式的一个结合,采用broker模式封装client和server之间的拓扑关系,而client和server的通信仍然按照请求应答 ...

    Convention插件

    考虑使用COnvention插件可以进行零配置而且插件进行很多规范的约定也可以对开发合作当中按着它相应的规律开发..感觉也挺方便管理的.下面简单介绍它的使用. 首先我们需要使用到的jar包: Java ...

    sshpass

    示例: ./sshpass -p ‘123456’  ssh -o StrictHostKeyChecking=no    root@192.168.1.15 ./sshpass -p ‘123456 ...

    vim spf13

    效果图来一个: http://vim.spf13.com/ 这个网站里面的vim配置非常全,推荐. 下面是对这个vim快捷键总结: 是"," 打卡一个 ...

    最简单的基于FFMPEG的封装格式转换器(无编解码)

    本文介绍一个基于FFMPEG的封装格式转换器.所谓的封装格式转换,就是在AVI,FLV,MKV,MP4这些格式之间转换(相应.avi,.flv,.mkv,.mp4文件).须要注意的是,本程序并不进行视 ...

    HTTPS抓包配置

    以Charles为例 配置Charles抓取Https需要手机和PC分别进行配置. 步骤: 1.PC下载charles客户端,并安装. 2.charles客户端安装证书 注意证书安装需要保存在&quo ...

    python的一些语法糖

    1   Python中if-else语句的多种写法 a, b, c = 1, 2, 3 1.常规 if a>b: c = a else: c = b 2.表达式 c = a if a>b  ...

    十个 PHP 开发者最容易犯的错误

    PHP 语言让 WEB 端程序设计变得简单,这也是它能流行起来的原因.但也是因为它的简单,PHP 也慢慢发展成一个相对复杂的语言,层出不穷的框架,各种语言特性和版本差异都时常让搞的我们头大,不得不浪费 ...

    Linux-Kconfig总结与分析

    使用Kconfig时,需要注意的地方 1.在Kconfig中定义的配置宏,前缀都没有"CONFIG_",只有编译内核时,自动生成autoconf.h才会出现前缀. 2.如果XX_d ...

    展开全文
  • 百度热力图数据是一种表征人群密度的数据,在涉及城市研究...百度将这些信息按照位置聚类,计算出各个地区聚类的人群密度,最后将计算结果用不同的颜色和亮度显示出来,用以反映人流量的空间差异。百度热力图有很强的时
  • Unity版本差异总结

    千次阅读 2021-11-17 15:42:18
    规范化了资源管理,统一了所有组件的获取方式,如之前animator,material无需在awake或者start函数进行获取,可直接使用,现在全部要使用getcomponent的形式进行获取, 5.x收编了ngui的开发团队,开始整合ugui; 5.3 ...
  • Android系统版本 版本特性 注意点 实现方案 Android 6.0 - SDK 23 动态权限控制 分为正常权限 、危险权限如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。如果您列出了危险权限,则用户必须...
  • 今天开发一需求时,要对A和B两List集合遍历,并比较出集合A有,而集合B没有的值。 比如说List集合A有’one’,‘two’,‘three’三值,List集合B有’one’,‘three’两值。 那么最终打印’two’。 下面我就用...
  • GEO数据表达差异分析

    2021-02-06 19:18:54
    1-1从GEO数据库下载数据rm(list = ls())options(stringsAsFactors = F)library(GEOquery)gse = "GSE4107"eSet destdir = '.',getGPL = F)1-2提取表达矩阵expexp head(exp)exp = log2(exp+1)dim(exp) #22样本,...
  • 文章目录第一节 地理空间及其表达第二节 空间数据采集第三节 属性数据采集第四节 空间数据格式转换第五节 空间数据质量 第一节 地理空间及其表达 1.1 地理空间 地理空间上至大气电离层,下至地幔莫霍面,是生命过程...
  • 获取财经数据神器akshare 基本使用总结

    万次阅读 多人点赞 2021-01-25 20:25:34
    AkShare是基于 Python 的开源数据接口库,目的是实现对期货、期权、基金等衍生金融产品和另类数据数据采集、数据清洗加工,、到数据下载的工具,满足金融数据科学家,数据科学爱好者在数据获取方面的需求。...
  • 在USGS网站中中点开Landsat数据级可以发现,其划分为两等级Collection1和Collection2两大类别。Collection1又被区分为3小级别...在进行大量数据下载的时候会发现存在获取数据前置有LC、LO以及LT三种类型。其中L
  • 那么什么是NDVI,NDVI有什么用,去哪里获取NDVI数据呢?让我们一起来看看吧! 什么是NDVI? NDVI,全名为Normalized Difference Vegetation Index,中文名称为归一化植被指数。这指数可以用来定性和定量评价植被...
  • 这里写目录标题数据获取David数据获取David数据分析KEGG绘图GO绘图CC绘图BP绘图 数据获取 David数据获取 David数据分析 KEGG绘图 GO绘图 CC绘图 BP绘图
  • SAS中获取数据集观测值

    千次阅读 2020-12-20 21:30:47
    好久没有更新文章了,上一次更新还是2015年10月25日,到现在已经15月了。坦白来讲,其实当时是计划按月来更新SAS编程的一些心得和体会的。鉴于当时我的SAS水平还是属于闭门造车的境界,且对于SAS语言的理解其实是...
  • 如何获取Pandas数据帧的行数?

    千次阅读 2020-12-24 04:40:46
    cs95..52如何获取大熊猫DataFrame的行数?下表总结了您希望在DataFrame(或Series,为了完整起见)中进行计数的不同情况,以及推荐的方法。脚注DataFrame.countSeries由于非空计数随列而异,因此返回一列的计数。...
  • 如何分析芯片数据我最早接触的高通量数据就是RNA-seq,后来接触的也基本是高通量测序结果而不是芯片数据,因此我从来没有分析过一次芯片数据,而最近有一学员在看生信技能树在腾讯课堂发布的课程GEO数据库表达芯片...
  • 从网络中获取债券收益率数据

    千次阅读 2021-11-14 21:09:24
    然而,忽略市场运动的基本力量的交易者对将基本数据纳入其交易决策的交易者不利。基于自动收集的基础数据的指标可以提高专家顾问的效率。对汇率影响最大的基础数据是利率,它影响货币的感知价值,虽然央行的利率没有...
  • 点击上方 "云祁QI"关注,星标或置顶一起成长如今,随着诸如互联网以及物联网等技术的不断发展,越来越多的数据被生产出来。据统计,每天大约有超过2.5亿亿字节的各种各样数据...
  • 近年来,信息技术迅猛发展,尤其是以互联网、物联网、信息获取、社交网络等为代表的技术日新月异,促使手机、平板电脑、pc 等各式各样的信息传感器随处可见,虚拟网络快速发展,现实世界快速虚拟化,数据的来源及其...
  • 第一章就先讲讲一些准备工作,包括数据获取、程序的框架、预处理这些。 数据获取 首先你需要获得猫狗的数据,建议去Kaggle官网上下,缺点就是Kaggle官网上的train包里猫狗的标签是分开的,但是test
  • 我们在MySql中想要对比下两不同的实例上的数据并且找出差异,除了主键之外我们还要对比字段,应该怎么做呢?方案一:写一程序将两实例里面的一行数据都分别取出来对比,但是耗时我们无法估计,大概...
  • 本着对ADC功能的学习与理解,以下内容讲解将使用两种方式读取数据(直接获取/DMA方式两种,具体差异后面会说明)并用串口打印,提供工程文件,希望对初学者有着一定帮助。 PS:内容均为原创,转
  • git 获取服务器代码

    2021-08-11 08:23:27
    git 获取服务器代码 内容精选换一换简要介绍Lsyncd实际上是...语言:Lua、C/C++一句话描述:数据同步工具开源协议:GPL-3.0建议的版本建议使用git获取最新版本。云服务器要求本文以云服务器KC1实例测登录Windows操作...
  • flink各版本变化和新增特性

    千次阅读 2021-03-17 09:29:57
    在Flink 1.6.0中,我们继续在较早版本中进行的基础工作:使Flink用户能够无缝地运行快速数据处理并毫不费力地构建数据驱动的数据密集型应用程序。 Flink的状态支持是使Flink在实现各种用例时如此通用和强大的关键...
  • 读透《华为数据之道》

    千次阅读 2020-12-28 07:30:00
    这是傅一平的第361篇原创【提醒:公众号推送规则变了,如果您想及时收到推送,麻烦右下角点在看,或者把本号置顶】正文开始很多年前阿里出了《大数据之路》一书,在数据技术层面给出了有价值的指...
  • “结束了吗?” “不用再每天工作到凌晨两点了吗...据说每个程序员都会至少参与一次数据迁移工作。如果想在轮到你的那一次痛苦少一点,我们不妨继续看下去。 为什么数据迁移项目难做 如果你没有做过数据迁移项目,很容
  • 某公司旗下有很多便利店,但近期却发现个别门店存在全职帮兼职打卡的情况,为此总部领导决定对所有门店的打卡时间数据进行分析,将门店,全职人员和兼职人员上班卡、下班卡其中之一相差1分钟以内的数据找出来...
  • MySQL--如何快速对比数据

    千次阅读 2021-01-18 18:55:30
    在MySQL运维中,研发同事想对比下两不同实例上的数据并找出差异,除主键外还需要对比字段,如何做呢?第一种方案,写程序将两实例上的一行数据取出来进行对比,理论可行,但是对比时间较长。第二种方案...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 223,045
精华内容 89,218
关键字:

获取每个版本的数据差异