当前位置: 首页 > 知识库问答 >
问题:

提高从数据库加载100000条记录的性能

东门清夷
2023-03-14

我们创建了一个程序,以便在其他程序中更容易地使用数据库。因此,我显示的代码将在多个其他程序中使用。

其中一个程序从我们的一个客户那里获得大约10000条记录,并且必须检查这些记录是否已经存在于我们的数据库中。如果没有,我们将它们插入数据库(它们也可以更改,然后必须更新)。

为了方便起见,我们从整个表中加载所有条目(目前为120,000个),为我们得到的每个条目创建一个类,并将它们全部放入Hashmap中。

这样装载整个桌子大约需要5分钟。此外,我们有时不得不重新启动程序,因为我们遇到了GC开销错误,因为我们在有限的硬件上工作。你知道我们如何提高性能吗?

下面是加载所有条目的代码(每个查询的全局限制为10.000个条目,因此我们使用循环):

public Map<String, IMasterDataSet> getAllInformationObjects(ISession session) throws MasterDataException {
    IQueryExpression qe;
    IQueryParameter qp;
    
    // our main SDP class
    Constructor<?> constructorForSDPbaseClass = getStandardConstructor();
    
    SimpleDateFormat itaTimestampFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
    
    // search in standard time range (modification date!)
    Calendar cal = Calendar.getInstance();
    cal.set(2010, Calendar.JANUARY, 1);
    Date startDate = cal.getTime();
    Date endDate = new Date();
    Long startDateL = Long.parseLong(itaTimestampFormat.format(startDate));
    Long endDateL = Long.parseLong(itaTimestampFormat.format(endDate));

    IDescriptor modDesc = IBVRIDescriptor.ModificationDate.getDescriptor(session);

    // count once before to determine initial capacities for hash map/set
    IBVRIArchiveClass SDP_ARCHIVECLASS = getMasterDataPropertyBag().getSDP_ARCHIVECLASS();
    qe = SDP_ARCHIVECLASS.getQueryExpression(session);
    qp = session.getDocumentServer().getClassFactory()
            .getQueryParameterInstance(session, new String[] {SDP_ARCHIVECLASS.getDatabaseName(session)}, null, null);        
    qp.setExpression(qe);  
    qp.setHitLimitThreshold(0);
    qp.setHitLimit(0);
    int nrOfHitsTotal = session.getDocumentServer().queryCount(session, qp, "*");
    int initialCapacity = (int) (nrOfHitsTotal / 0.75 + 1);

    // MD sets; and objects already done (here: document ID)
    HashSet<String> objDone = new HashSet<>(initialCapacity); 
    HashMap<String, IMasterDataSet> objRes = new HashMap<>(initialCapacity); 
    
    qp.close();
    
    // do queries until hit count is smaller than 10.000
    // use modification date
    
    boolean keepGoing = true;
    while(keepGoing) {
        // construct query expression
        // - basic part: Modification date & class type
        // a. doc. class type
        qe = SDP_ARCHIVECLASS.getQueryExpression(session);
        // b. ID
        qe = SearchUtil.appendQueryExpressionWithANDoperator(session, qe, 
                   new PlainExpression(modDesc.getQueryLiteral() + " BETWEEN " + startDateL + " AND " + endDateL));
        
        // 2. Query Parameter: set database; set expression
        qp = session.getDocumentServer().getClassFactory()
                .getQueryParameterInstance(session, new String[] {SDP_ARCHIVECLASS.getDatabaseName(session)}, null, null);
        
        qp.setExpression(qe);  
        
        // order by modification date; hitlimit = 0 -> no hitlimit, but the usual 10.000 max
        qp.setOrderByExpression(session.getDocumentServer().getClassFactory().getOrderByExpressionInstance(modDesc, true));
        qp.setHitLimitThreshold(0);
        qp.setHitLimit(0);

        // Do not sort by modification date;
        qp.setHints("+NoDefaultOrderBy");
        
        keepGoing = false;
        IInformationObject[] hits = null;
        IDocumentHitList hitList = null;
        hitList = session.getDocumentServer().query(qp, session);
        IDocument doc;
        if (hitList.getTotalHitCount() > 0) {
            hits = hitList.getInformationObjects();
            for (IInformationObject hit : hits) {
                String objID = hit.getID();
                if(!objDone.contains(objID)) {
                    // do something with this object and the class
                    // here: construct a new SDP sub class object and give it back via interface
                    doc = (IDocument) hit;
                    IMasterDataSet mdSet;
                    try {
                        mdSet = (IMasterDataSet) constructorForSDPbaseClass.newInstance(session, doc);
                    } catch (Exception e) {
                        // cause for this
                        String cause = (e.getCause() != null) ? e.getCause().toString() : MasterDataException.ERRMSG_PART_UNKNOWN;                            
                        throw new MasterDataException(MasterDataException.ERRMSG_NOINSTANCE_POSSIBLE, this.getClass().getSimpleName(), e.toString(), cause);
                    }                        
                    objRes.put(mdSet.getID(), mdSet);
                    objDone.add(objID);
                }                       
            }
            doc = (IDocument) hits[hits.length - 1];
            Date lastModDate = ((IDateValue) doc.getDescriptor(modDesc).getValues()[0]).getValue();
            startDateL = Long.parseLong(itaTimestampFormat.format(lastModDate));
        
            keepGoing = (hits.length >= 10000 || hitList.isResultSetTruncated());
        }
        qp.close();
    }   
    return objRes;
}

共有1个答案

鱼恩
2023-03-14

每次加载120000行(或更多)将无法很好地扩展。

表需要具有基于记录列的主键或唯一键。迭代执行JDBCSQL更新的10,000条记录,以修改所有字段值,使其与where子句完全匹配主/唯一键。

update BLAH set COL1 = ?, COL2 = ? where PKCOL = ?; // ... AND PKCOL2 =? ...

这会修改现有行或根本不做任何操作,JDBCexecuteUpdate()将返回0或1,指示更改的行数。如果更改的行数为零,则检测到一条不存在的新记录,因此仅对该新记录执行insert。

insert into BLAH (COL1, COL2, ... PKCOL) values (?,?, ..., ?);

您可以决定是运行10000次更新,然后再执行需要多少次插入,还是执行可选的更新插入,记住JDBC批处理语句/自动提交关闭可能有助于加快速度。

 类似资料:
  • 问题内容: 我在公司中多次设计数据库。为了提高数据库的性能,我只寻找标准化和索引。 如果要求您提高数据库的性能,该数据库包含大约250个表以及一些具有数百万个记录的表,那么您将寻找什么不同的东西? 提前致谢。 问题答案: 优化逻辑设计 逻辑级别是关于查询和表本身的结构。首先尝试最大程度地发挥这一作用。目标是在逻辑级别上访问尽可能少的数据。 拥有最高效的SQL查询 设计支持应用程序需求的逻辑架构(例

  • 我有三个类具有类层次结构 > < Li > < p > < code > parent class . Java 具有用于此ChildClass1的属性,它还使用来自父类的一些常见属性 < code>ChildClass2扩展ParentClass 具有用于此子类2的属性,它还使用父类中的一些公共属性 所有这些属性都包含在两列表中 现在我不确定如何从Hibernate继承加载它们? 为愚蠢的问题道

  • 问题内容: 有一个数据库,它在一个表中大约包含200万条记录。我从我的Java代码中运行查询,例如“ select * from table”。是否将从结果集中的数据库中获取完整数据。或不 。如果是,那么它将如何工作,我想学习此检索工作, 请让我知道,我在某处了解到它将从数据库中检索完整的数据并将其存储在临时存储中,并在输出中显示出来。还是与J2C有关 问题答案: 它会从结果集中的数据库中获取完整

  • 本文向大家介绍mysql技巧:提高插入数据(添加记录)的速度,包括了mysql技巧:提高插入数据(添加记录)的速度的使用技巧和注意事项,需要的朋友参考一下 问题描述: 普通台式机,采集数据,表中已经有>1000万数据量。 采集回来的数据插入表中的时候很慢,每条约100毫秒。 解决方法: 1、加大mysql配置中的bulk_insert_buffer_size,这个参数默认为8M bulk_inse

  • 我们正在快速开发一个应用程序,其中我们需要一次获取超过50K行(在应用程序加载时执行),然后数据将用于应用程序的其他部分进行进一步计算。我们正在使用Firebase实时数据库,我们面临一些严重的性能问题。 它目前需要大约40秒才能加载50K行(目前使用的是免费数据库版本,不确定这是否是原因),但我们也观察到,当多个用户使用该应用程序时,加载50K行开始需要大约1分20秒,Peak达到100%。 您

  • 我正在尝试使用ajax发送表单数据。我的索引页面记录是在使用ajax从远程页面获取后显示的。 下面是我的页面图片。 每个记录都有注释框,我想使用ajax将这些注释存储在数据库中。 下面是我的jquery 我在单击时使用了,因为这些记录是从远程页面加载的。我的表格在下面 现在当我点击帖子时,评论正在为最后一条记录工作。我需要发送ID号和文本区值到PHP页面更新在mysql,但两个评论都显示相同的记录