【问题标题】:How to use DataTable (or similar) with Oracle DB如何在 Oracle DB 中使用 DataTable(或类似的)
【发布时间】:2018-11-14 09:03:58
【问题描述】:

我最近一直在处理一些性能问题,并试图弄清楚如何以指数方式提高对 Oracle 数据库的某些调用的性能。

技术:

  • .NET Core 2
  • Oracle 数据库
  • 小巧玲珑(可选)
  • Devart(可选)
  • OracleManaged(可选,测试版)

我熟悉 DataTable 和 Dapper 和 SQL Server 的表值参数的使用,并希望通过上述技术复制它们。我还无法重现以下解决方案以与 Devart 或 OracleManaged 一起使用:

下面的代码不是我正在运行的......这是一个转述的例子。我只需要与 Oracle 配合使用的东西来传递要在查询/插入中使用的 DataTable 或对象数组。

SQL 服务器:

CREATE TYPE MyCustomerInfo AS TABLE
(
    Id BIGINT NOT NULL,
    --Name NVARCHAR(32) NOT NULL,
    --...
);

用于 SQL Server 的 C#:

const string getCustomersSql = @"
    SELECT
        c.Id,
        --c.Name
        --...
    FROM @myCustomers mc
    LEFT JOIN Customers c
        ON c.Id = mc.Id";

var myCustomers = new DataTable();
myCustomers.Columns.Add("Id", typeof(long));
//...

myCustomers.Rows.Add(1);
myCustomers.Rows.Add(2);

var customers = await sqlDbConnection.QueryAsync<Customer>(getCustomersSql, new { myCustomers = myCustomers.AsTableValuedParameter("MyCustomerInfo") });

Oracle 数据库 (PL/SQL):

CREATE TYPE MY_CUSTOMER_INFO AS OBJECT
(
    ID BIGINT,
    --NAME VARCHAR2(32),
    --...
);

CREATE TYPE MY_CUSTOMER_INFO_ARRAY AS TABLE OF MY_CUSTOMER_INFO;

C# for Oracle DB:

我采用了与 SQL Server 类似的方法,但同时使用了 Devart 和 OracleManaged,但均未奏效。我也 [非常不高兴] 尝试直接使用 OracleCommandOracleParameter - 再次使用 Devart 和 OracleManaged - 无济于事。

我对 Devart 的结果似乎表明该功能是故意阻止的。我对 OracleManaged 的​​结果似乎表明它尚未实施,这并不奇怪,因为它是 beta 版(预计今年第三季度发布)。

我的下一个方法可能是在 Devart 中使用关联数组(我对这些数组几乎没有经验或渴望学习)。在这一点上,我只是在探索可以带来类似性能提升的东西......

编辑:使用每个参数数组的方法是可能的,但非常不方便,因为大型类最终会包含 12 个以上的数组。我想要这种方法的替代方法。

【问题讨论】:

  • 这是stackoverflow.com/questions/49739027/… 的副本吗?即使不是,我认为我的回答可能很好读:)
  • 此外,ODP.NET 托管驱动程序不支持 oracle UDT 和 .NET 类型之间的映射。 docs.oracle.com/database/121/ODPNT/featUDTs.htm#ODPNT379
  • 映射到底是什么? MY_CUSTOMER_INFO_ARRAY 的 DataTable?我不需要映射输出。
  • 是的,这种映射必须发生在 .NET 驱动程序中,Oracle 在我链接的页面中特别指出,在 ODP.NET 托管的 ODP.NET 中不支持将 .NET 类型自定义映射到用户数据类型司机。您正在谈论将 DataTable 映射到 UDT,而不是自定义类 - 我在文档中找不到任何具体的内容,也许这是可行的。
  • 无论如何,要使其通过 Dapper 工作,您必须将参数包装在自定义 ICustomQueryParameter 中。 dapper 的 TableValuedParameter 仅针对 SQL server 实现 - github.com/StackExchange/Dapper/blob/master/Dapper/…

标签: c# oracle dapper .net-core-2.0 devart


【解决方案1】:

@Kody 这篇文章有点老了,所以这可能对你没有帮助,但对其他人来说可能会有所帮助。虽然我不知道有任何方法可以将数据表/UDT 与托管 Oracle 客户端一起使用,但如果您只是想减少到数据库的往返次数并通过一次调用来执行一堆插入/删除/更新您可以尝试这种方法的数据库:

using (var dbConn = ManagedOracleHelper.GetConnection())
{
    dbConn.Open();
    var cmd = dbConn.CreateCommand();
    var udtList = GetUDTList(); // A dummy method to get a collection of Model 
                                // objects you want to use for the bulk operation.
                                // This could be a dataset too, you would just need
                                // to change the code within the for-loop to iterate
                                // over rows and access the columns by name.

    var firstNameArr = new string[udtList.Count];
    var lastNameArr  = new string[udtList.Count];
    var emailArr     = new string[udtList.Count];

    for (var i = 0; i < udtList.Count; i++)
    {
        firstNameArr[i] = udtList[i].FirstName;
        lastNameArr[i]  = udtList[i].LastName;
        emailArr[i]     = udtList[i].Email;
    }

    cmd.CommandText = @"INSERT INTO CUSTOMERS(FIRST_NAME, LAST_NAME, EMAIL)
                        VALUES(:FirstName, :LastName, :Email)";;
    cmd.BindByName  = true;

    cmd.Parameters.Add("FirstName", OracleDbType.Varchar2, ParameterDirection.Input);
    cmd.Parameters.Add("LastName", OracleDbType.Varchar2, ParameterDirection.Input);
    cmd.Parameters.Add("Email", OracleDbType.Varchar2, ParameterDirection.Input);

    cmd.ArrayBindCount = udtList.Count;

    cmd.Parameters["FirstName"].Value = firstNameArr;
    cmd.Parameters["LastName"].Value  = lastNameArr;
    cmd.Parameters["Email"].Value     = emailArr;

    cmd.ExecuteNonQuery();
}

不确定如果您要插入/更新数亿条记录,其性能如何,但我已经通过插入 80K 记录对此进行了测试,并且我的导入功能从需要数分钟(以前有人将其编码为简单的循环调用)每条记录的插入)减少到几秒钟。我没有确切的数字,因为一旦导入时间减少了近 2 个数量级,我很高兴可以继续做其他事情。

【讨论】:

  • 这是关联数组方法。这与我最终做的类似,但非常不方便。要对 SQL Server 进行大量插入,您基本上只需将列表对象直接传递给 SQL 查询,它的运行速度非常快。幸运的是,我不必再直接访问 Oracle DB。这不是我要找的答案,但无论如何谢谢。
  • 是的,令人难以置信的是,有人愿意使用 Oracle。我想念我的 SQL Server 日子。也许这可能会帮助与我们有类似挫败感的其他人;-)
猜你喜欢
  • 2019-06-08
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
  • 2020-05-12
  • 1970-01-01
  • 2015-10-30
  • 2023-01-24
  • 2021-12-02
相关资源
最近更新 更多