You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure CosmosDB Java SDK:容器全量查询与高效删除问题

问题解答

1. 修复全量查询代码

你的代码问题出在每次循环都重新创建迭代器:filteredFamilies.iterator()每次调用都会返回新的迭代器实例,导致每次都从第一个元素开始遍历,最终无限循环输出同一条数据。

修复方案是先获取一次迭代器,再基于这个迭代器完成循环:

private void queryDocuments() throws Exception {
    logger.info("Query documents in the container " + containerName + ".");

    String sql = "SELECT * FROM c";
    CosmosPagedIterable<Family> filteredFamilies = container.queryItems(
        sql,
        new CosmosQueryRequestOptions(),
        Family.class
    );

    // 仅初始化一次迭代器
    Iterator<Family> iterator = filteredFamilies.iterator();
    while (iterator.hasNext()) {
        Family family = iterator.next();
        logger.info(
            "Query result: Family with (/id, partition key) = (%s,%s)",
            family.getId(),
            family.getLastName()
        );
    }

    logger.info("Done.");
}

如果数据量较大,还可以利用CosmosPagedIterable的分页特性,手动处理每一页数据:

for (FeedResponse<Family> page : filteredFamilies.iterableByPage()) {
    logger.info("Got a page of results, size: " + page.getResults().size());
    for (Family family : page.getResults()) {
        logger.info(
            "Family with (/id, partition key) = (%s,%s)",
            family.getId(),
            family.getLastName()
        );
    }
}

2. 高效删除容器内所有项的方法

逐个删除文档效率极低,推荐以下几种高效方案:

方案一:使用批量删除操作(Java SDK v4+)

SDK v4支持批量操作,开启后可一次性提交多个删除请求,大幅减少网络往返开销。

首先确保客户端配置开启批量执行:

CosmosClient cosmosClient = new CosmosClientBuilder()
    .endpoint(ENDPOINT)
    .key(KEY)
    .enableBulkExecution(true) // 开启批量特性
    .buildClient();

然后批量删除所有文档:

private void bulkDeleteAllDocuments() throws Exception {
    // 仅查询id和分区键,减少数据传输量
    String sql = "SELECT c.id, c.lastName FROM c";
    CosmosPagedIterable<Family> families = container.queryItems(
        sql,
        new CosmosQueryRequestOptions(),
        Family.class
    );

    List<CosmosItemOperation> deleteOperations = new ArrayList<>();
    for (Family family : families) {
        deleteOperations.add(
            CosmosItemOperation.deleteItem(
                family.getId(),
                new PartitionKey(family.getLastName())
            )
        );
    }

    // 执行批量删除
    container.executeBatch(deleteOperations);
    logger.info("Bulk delete completed.");
}

方案二:使用服务器端存储过程

在CosmosDB中创建存储过程,直接在服务器端执行删除逻辑,彻底避免多次网络往返,适合超大量数据的删除场景。

存储过程示例(JavaScript):

function deleteAllDocuments() {
    var collection = getContext().getCollection();
    var query = 'SELECT * FROM c';
    var continuationToken = null;

    function deleteBatch(documents) {
        if (documents.length === 0) {
            getContext().getResponse().setBody("All documents deleted successfully.");
            return;
        }
        var batchSize = documents.length;
        var deletedCount = 0;

        documents.forEach(function(doc) {
            collection.deleteDocument(doc._self, function(err) {
                if (err) throw err;
                deletedCount++;
                if (deletedCount === batchSize) {
                    queryNext();
                }
            });
        });
    }

    function queryNext() {
        var requestOptions = { continuation: continuationToken };
        collection.queryDocuments(collection.getSelfLink(), query, requestOptions, function(err, docs, responseOptions) {
            if (err) throw err;
            continuationToken = responseOptions.continuation;
            deleteBatch(docs);
        });
    }

    queryNext();
}

用Java SDK调用该存储过程:

private void executeDeleteStoredProcedure() throws Exception {
    CosmosStoredProcedureResponse response = container.getScripts()
        .getStoredProcedure("deleteAllDocuments")
        .execute(null, new CosmosStoredProcedureRequestOptions());
    logger.info("Stored procedure execution result: " + response.getResponseBody());
}

方案三:按分区键批量删除

如果容器有明确的分区键,可以遍历所有分区键值,针对每个分区批量删除文档,避免全表扫描的性能开销:

private void deleteByPartitionKeys() throws Exception {
    // 查询所有唯一的分区键值
    String partitionQuery = "SELECT DISTINCT c.lastName FROM c";
    CosmosPagedIterable<Map<String, String>> partitionKeys = container.queryItems(
        partitionQuery,
        new CosmosQueryRequestOptions(),
        Map.class
    );

    for (Map<String, String> pkMap : partitionKeys) {
        String partitionKey = pkMap.get("lastName");
        // 针对当前分区查询所有文档的id
        String sql = "SELECT c.id FROM c WHERE c.lastName = @pk";
        SqlParameter parameter = new SqlParameter("@pk", partitionKey);
        CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
        options.setPartitionKey(new PartitionKey(partitionKey));

        CosmosPagedIterable<Family> families = container.queryItems(
            sql,
            options,
            Family.class
        );

        // 批量删除该分区的文档
        List<CosmosItemOperation> deleteOps = new ArrayList<>();
        for (Family family : families) {
            deleteOps.add(CosmosItemOperation.deleteItem(family.getId(), new PartitionKey(partitionKey)));
        }
        container.executeBatch(deleteOps);
        logger.info("Deleted all documents in partition: " + partitionKey);
    }
}

内容的提问来源于stack exchange,提问作者user1843591

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:35:18