基于传统数据查询慢的优化方案

1、背景

          由于业务系统使用的是传统关系型数据库sqlserver、mysql,数据随着时间的日积月累,导致数据量不断增大,最后导致系统的查询性能比较低下,用户体检非常不友好。

在传统关系型数据库上,适合使用solr作为优化方式的几种情况:

          1)、基于字段的模糊查询

          2)、单表数据量过大,创建索引之后查询依旧比较慢     

    下面简单介绍一下基于solr来优化查询效率的一种实现方式。

2、solr安装:以windows为例

          Solr是一个高性能,采用Java开发。Solr基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的搜索引擎。

          Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。

          Solr 的特征:
                 高级全文搜索能力:由Lucene ™提供支持,Solr可实现强大的匹配功能,包括短语,通配符,联接,分组以及任何数据类型
                 针对大容量流量进行了优化:
                 拥有基于标准的开放式接口- XML、JSON 和 HTTP
                 综合的管理界面
                 实现轻松监控
                 高度的可扩展性和容错性
                 灵活的适应性,易于配置
                 能够实时索引
                 可扩展的插件架构

solr链接

                    Solr 各版本下载地址:Index of /dist/lucene/solr

                    本手册翻译自 Solr 官方网站:Resources - Apache Solr

                    详细的solr中文手册链接:Solr官方文档_w3cschoolSolr采用Java5开发,是建立在Apache Lucene上的流行的、快速的开源企业搜索平台。Solr具有高度可靠、可伸缩和容错能力,提供分布式索引、复制和负载平衡查询、自动故障转移和恢复、集中配置等功能。_来自Solr官方文档,w3cschool编程狮。https://www.w3cschool.cn/solr_doc/

solr安装

                   在安装solr之前,首先保证已经正确安装了Java。

                   solr从6.0之后需要Java1.8,所以如果使用Solr6.0及其以上版本,请确保Java版本在1.8之上

                   将Solr下载之后解压在电脑的某个目录,我解压到了C盘目录下.

1)、下载解压之后,solr的结构说明:如下图

 

 

正在上传…重新上传取消

2)、安装

  1. 将solr-7.7.0.zip文件拷贝到C盘;(或者其他盘都可以,只要目录中不要出现中文就行。)
  2. 解压solr-7.7.0.zip文件,得到solr-4.10.2目录。
  3. 进入solr的bin目录中,运行cmd 执行命 solr.cmd start 如下图所示:正在上传…重新上传取消

3)、启动:浏览器中输入:http://localhost:8983/solr/

正在上传…重新上传取消 

到此,solr就安装成功了

solr创建Core

创建core有两种方式:通过界面操作创建;通过命令创建

通过界面操作创建:

1)、在C:\home\solr-7.7.0\server\solr内创建一个core_01文件夹:

 

正在上传…重新上传取消


2)、将C:\home\solr-7.7.0\server\solr\configsets\sample_techproducts_configs\conf文件夹复制到core_01内
3)、修改core_demo/conf/solrconfig.xml文件,一般不需要修改
4)、在http://localhost:8983/solr内添加core_01实例,实例名称一定要与您第一步创建的文件夹名称相同

 

正在上传…重新上传取消

通过命令创建:

进入solr安装bin,执行一下命令:

solr.cmd create -c core_01

设置中文分词器

将中文分词器的jar放到C:\home\solr-7.7.0\server\solr-webapp\webapp\WEB-INF\lib

 

正在上传…重新上传取消

找到要配置分词器的core下面的managed-schema文件,添加一下内容:

 

正在上传…重新上传取消










3、solr和spring boot项目整合

整合依赖

org.springframework.bootspring-boot-starter-data-solr

配置application.properties

spring.data.solr.host=http://localhost:8983/solr

简单写一下模糊查询接口api

@Override
public List searchByName(String keywords) throws Exception {//创建查询SolrQuery query = new SolrQuery();System.out.println("输出参数:"+keywords);//精准查询,查询关键词用英文双引号query.setQuery("st_name:\""+keywords+"\"");//模糊查询,关键词不需要双引号//query.setQuery("st_name:"+keywords);QueryResponse res = solrClient.query("result_am_electro_data", query);//获取结果集SolrDocumentList results = res.getResults();System.out.println("输出结果:"+results.getNumFound());List list = new ArrayList<>();if(results.getNumFound() > 0){for(SolrDocument doc:results){result_am_electro_data en = new result_am_electro_data();en.setApp_pc(Double.valueOf(doc.get("acc_pc").toString()));en.setGuid(doc.get("guid").toString());en.setId(doc.get("id").toString());en.setSt_code(doc.get("st_code").toString());en.setSt_name(doc.get("st_name").toString());en.setTm(doc.get("tm").toString());en.setSt_lang(BigDecimal.valueOf(Double.valueOf(doc.get("st_long").toString())));en.setSt_lat(BigDecimal.valueOf(Double.valueOf(doc.get("st_lat").toString())));list.add(en);}}return list;
}

4、solr数据初始化方式

       将数据库数据初始化到solr中,比较常用的两种方式有通过配置文件进行初始化,也可以通java API方式同步,下面介绍一下sqlserver数据同步到solr的两种方式。

通过配置文件:

1、先将sqlserver的驱动包以及solr同步的依赖包拷贝到C:\home\solr-7.7.0\server\solr-webapp\webapp\WEB-INF\lib:

 

正在上传…重新上传取消

2、创建solr的core,这里使用命令创建:solr.cmd create -c core_02

3、然后修改配置文件

进入core_02的conf目录,修改solrconfig.xml配置文件,修改内容如下:

标签后填写如下内容


  
   data-config.xml
  

再conf目录下创建data-config.xml文件,内容如下

3.1单表同步至solr的data-config.xml配置:



url = "jdbc:sqlserver://172.18.255.197:1433;DatabaseName=sy_bigdata" user="sa" password = "atmk!123"
encoding="UTF-8"/>

query = "select contno,prtno,appntno,create_date from lccont">






单表最后再修改conf下的managed-schema,修改内容如下



3.2多表关联查询结果同步至solr的data-config.xml配置:



url = "jdbc:sqlserver://172.18.255.197:1433;DatabaseName=sy_bigdata" user="sa" password = "atmk!123"
encoding="UTF-8"/>

query = "select contno,prtno,appntno,create_date from lccont">









多表关联最后再修改conf下的managed-schema,修改内容如下





4、重启solr,在页面上进行如下操作,即可将数据从sqlserver同步到solr中

停止命令:solr.cmd stop all

启动命令:solr.cmd start

 

正在上传…重新上传取消

或者直接点击下面链接即可实现全量导入:

http://localhost:8983/solr/core_04/dataimport?command=full-import&clean=true&commit=true&wt=json&indent=true&verbose=false&optimize=false&debug=false&id=1

5、简单查询一下同步结果

 

正在上传…重新上传取消

通过API方式

通过编写solr API方式将sqlserver数据同步到solr中,此代码参数主要有要同步的solrcore名称,关系型表的主键、数据库用户名、密码、驱动器、数据库连接地址、要操作的数据库名称、solr连接地址以及同步方式(增量同步还是初始化),

因此一个代码可以实现增量和全量的自动切换。

具体代码如下:

public class SyncDateToSolr {public static void main(String[] args) {String tableName = "";String uniqueKey = "";String userName = "";String password = "";String driver = "";String solrurl = "";String dburl = "";String db = "";String mode = "";if(args.length < 9){System.out.println("程序没有参数退出");System.exit(0);}else{tableName = args[0];uniqueKey = args[1];userName = args[2];password = args[3];driver = args[4];solrurl = args[5];dburl = args[6];db = args[7];mode = args[8];}Properties proper = GetProperties.getProper();String sql = proper.getProperty(tableName);String sqlUrl = dburl+";DatabaseName="+db;try {saveSqlserverToSolr(tableName,uniqueKey,sql,userName,password,driver,solrurl,sqlUrl,mode);} catch (Exception e) {e.printStackTrace();}System.out.println("程序执行结束");}public static void saveSqlserverToSolr(String core,String key,String sql,String USERNAME,String PASSWORD,String DRIVERNAME,String solrUrl,String sqlurl,String mode) throws Exception{String yesday = DateUtil.getYesterDate();String solrurl = "";String selectSqlInc = "";if(mode.equals("inc")){selectSqlInc = sql + yesday+"';";solrurl = solrUrl+core;}else{selectSqlInc = sql;core=core.replaceAll("\\d+","");solrurl = solrUrl+core;}Connection connection;PreparedStatement preparedStatement;HttpSolrClient solrClient = new HttpSolrClient.Builder(solrurl).withConnectionTimeout(10000).withSocketTimeout(60000).build();Class.forName(DRIVERNAME);connection = DriverManager.getConnection(sqlurl, USERNAME, PASSWORD);System.out.println("拼接sql:"+selectSqlInc);Statement sm = connection.createStatement();ResultSet rs = sm.executeQuery(selectSqlInc);ResultSetMetaData metaData = rs.getMetaData();int count = metaData.getColumnCount();String[] keys = key.split(",");StringBuffer sb = new StringBuffer();int m=0;while (rs.next()) {SolrInputDocument doc = new SolrInputDocument();for(int i = 1;i <= count;i++){String columnName = metaData.getColumnName(i);String value = rs.getString(columnName);for(int j = 0;j < keys.length;j++){if(keys[j].equals(columnName)){sb.append(value).append("_");}else{continue;}}doc.setField(columnName,value);}sb.delete(sb.length()-1,sb.length());doc.setField("id", sb.toString());sb.delete(0,sb.length());solrClient.add(doc);m++;System.out.println("已经处理:"+m+"条数据了");}solrClient.commit();solrClient.close();sm.close();connection.close();}

}

代码中读取配置文件的代码如下:

public class GetProperties {public static Properties getProper() {Properties properties = new Properties();try {//增量,一天
// InputStream is = GetProperties.class.getClassLoader().getResourceAsStream("inc_sql.properties");//全量InputStream is = GetProperties.class.getClassLoader().getResourceAsStream("full_sql.properties");properties.load(is);} catch (Exception e) {e.printStackTrace();}return properties;}

}

其中full_sql.properties的文件内容如下:

am_message_info1=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021110'
am_message_info2=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021111'
am_message_info3=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021112'
am_message_info4=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021113'
am_message_info5=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021100'
am_message_info6=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021101'
am_message_info7=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021102'
am_message_info8=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021103'
am_message_info9=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021090'
am_message_info10=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021091'
am_message_info11=select massid,guid,massage,tm from am_message_info where left(CONVERT(varchar(100), tm, 112),7)='2021092'

此代码的是打包上传到linux执行,架包的名称为:Solr_Study-1.0-SNAPSHOT.jar,具体执行的脚本如下:

#!/bin/bash
#while [ true ]
#do
#数据库用户名
username=sa
password=atmk!123
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
solrurl=http://172.18.255.197:8983/solr/
dburl=jdbc:sqlserver://172.18.255.197:1433
db=sy_bd
mode=full
#获取当前小时
h=`date "+%H"`
#获取当前分钟
m=`date "+%M"`
#每天凌晨3点10分跑定时任务
if [[ $h -eq 15 ]] && [[ 4 -eq 4 ]];then
echo "进入if条件判断"
fi
dir=$(cd "$(dirname "$0")"; pwd)
confpath=${dir}/conf
for line in `cat ${confpath}/inc_save_data.properties`
do

table_flag=${line%%:*}
if [ x$table_flag == x"exe_table" ];then
table_nm=${line%%\#*}

table_nm=${table_nm:10}

line=${line#*\#}
key_flag=${line%%:*}
key=""

if [ x${key_flag} == x"key" ];then
key=${line%%\#*}

key=${key:4}
java -jar Solr_Study-1.0-SNAPSHOT.jar $table_nm $key $username $password $driver $solrurl $dburl $db $mode

fi
fi
done

其中配置文件inc_save_data.properties内容如下:

exe_table:am_message_info1#key:massid#
exe_table:am_message_info2#key:massid#
exe_table:am_message_info3#key:massid#
exe_table:am_message_info4#key:massid#
exe_table:am_message_info5#key:massid#
exe_table:am_message_info6#key:massid#
exe_table:am_message_info7#key:massid#
exe_table:am_message_info8#key:massid#
exe_table:am_message_info9#key:massid#
exe_table:am_message_info10#key:massid#
exe_table:am_message_info11#key:massid#
exe_table:am_message_info12#key:massid#
exe_table:am_message_info13#key:massid#
exe_table:am_message_info14#key:massid#
exe_table:am_message_info15#key:massid#

5、solr索引增量同步方式

5.1 通过配置方式实现增量同步:

5.1.1、修改data-config.xml内容:



url = "jdbc:sqlserver://172.18.255.197:1433;DatabaseName=sy_bigdata" user="sa" password = "atmk!123"
encoding="UTF-8"/>

query = "select contno,prtno,appntno,create_date from lccont"
deltaImportQuery="select contno,prtno,appntno,create_date from lccont where contno='${dih.delta.contno}'"
deltaQuery="select contno from lccont where create_date > '${dih.last_index_time}'"
>







5.1.2 再修改managed-schema,内容如下:




注意:用于增量的字段类型设置成pdate

或者定时访问下面链接即可实现增量导入:

http://localhost:8983/solr/core_04/dataimport?command=delta-import&clean=false&commit=true&wt=json&indent=true&verbose=false&optimize=false&debug=false

5.2 实时性要求高的话,可以在调用接口时调用api方式同步数据

5.2.1 假如新增或修改一条数据时,也将数据同步到solr的代码实现方式

再执行保存数据到sqlserver时,也调用保存数据到solr的接口,实现数据实时同步

//将数据保存到sqlserver代码:

@Insert("insert into AM_ELECTRO_DATA(guid,tm,acc_pc) values(#{guid},#{tm},#{acc_pc})")
public void saveData(AM_ELECTRO_DATA_TWO en);

//将数据保存到solr代码

@Override
public void saveData(AM_ELECTRO_DATA_TWO en) throws Exception {SolrInputDocument doc = new SolrInputDocument();doc.addField("id",en.getGuid());doc.addField("guid",en.getGuid());doc.addField("tm",en.getTm());doc.setField("acc_pc",en.getAcc_pc());solrClient.add(doc);//solrClient.commit("AM_ELECTRO_DATA");solrClient.commit();
}

5.2.2 在进行删除数据时,同时删除sqlserver和solr

//删除sqlserver数据代码

@Delete("delete from AM_ELECTRO_DATA where guid=#{id}")
public void deleteByID(String id);

//删除solr数据代码

@Override
public void deleteByID(String id) throws Exception {//solrClient.deleteById("AM_ELECTRO_DATA",id);solrClient.deleteById(id);solrClient.commit();
}

5.3 实时性要求不高的话,可以T+1调用API方式同步的方式:

api的方式和初始化的api是一样的,就是将shell脚本中的mode有full改为inc即可

6、sqlserver和solr性能对比

总之来说,solr在数据量比较大和模糊查询性能要比sqlserver高很多

6.1 数据量为8263649性能对比

sqlserver耗时:0.566

 

正在上传…重新上传取消

solr耗时:0.960

 

正在上传…重新上传取消

6.2 数据量为34898880性能对比

sqlserver耗时:6.527

 

正在上传…重新上传取消

solr耗时:0.912

 

正在上传…重新上传取消

6.3 数据量为一亿两千万的数据

sqlserver耗时:55.528

 

正在上传…重新上传取消

solr耗时:0.354

 

正在上传…重新上传取消

6.4 模糊查询性能对比

数据量:8263649

sqlserver查询用时:68.394

 

正在上传…重新上传取消

solr查询用时:0.346

 

正在上传…重新上传取消


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部