0

I want to use Apache Ignite as a caching layer, and I am trying to load a table into the cache. I have a .NET console project where I use Oracle.ManagedDataAccess.Client to go through every row in TABLE.

TABLE has 500,000 entries and its size is around 300MB.

Executing the C# code takes ~50 minutes. However, executing SELECT * FROM TABLE takes about 250 msecs to load 500 entries in Toad and, at most, 65 seconds for all 500,000 entries.

Program.cs:

class Program
{
    static void Main(string[] args)
    {

        // Create Connection
        OracleConnection con = new OracleConnection();

        // Create ConnectionString using Builder
        OracleConnectionStringBuilder ocsb = new OracleConnectionStringBuilder();
        ocsb.Password = "PASSWORD";
        ocsb.UserID = "USER";
        ocsb.DataSource = "URL";

        // Connect 
        con.ConnectionString = ocsb.ConnectionString;
        con.Open();
        Console.WriteLine();
        Console.WriteLine(">>> Connection Established");

        // Execute a SQL SELECT
        OracleCommand cmd = con.CreateCommand();
        cmd.CommandText = "select * from TABLE";
        OracleDataReader reader = cmd.ExecuteReader();

        // Cache configuration
        var cfg = new IgniteConfiguration
        {
            PeerAssemblyLoadingMode = Apache.Ignite.Core.Deployment.PeerAssemblyLoadingMode.CurrentAppDomain,
            CacheConfiguration = new[]
            {
                new CacheConfiguration
                {
                    Name = "cacheName",
                    Backups = 1,
                    QueryEntities = new[]
                    {
                        new QueryEntity(typeof(int), typeof(Table))
                    }
                }
            }
        }

        IIgnite ignite = Ignition.Start(cfg);
        ICache<int, Table> cache = ignite.GetOrCreateCache<int, Table>("cacheName");


        using (var stmr = ignite.GetDataStreamer<int, Table>("cacheName"))
        {
            // Add entries to cacheName
            while (reader.Read())
            {
                Table table = new Table();
                table.SetObject(reader);
                stmr.AddData(table.Id, table.Name);
            }
            // Clean up
            reader.Dispose();
            cmd.Dispose();
            con.Dispose();
        }
    }
}

Table.cs:

class Table
    {
        [QuerySqlField(IsIndexed = true)]
        public int Id { get; set; }
        [QuerySqlField]
        public string Name { get; set; }

        public void SetObject(OracleDataReader reader)
        {
            Id = reader.IsDBNull(0) ? 0 : reader.GetInt32(0);
            Name = reader.IsDBNull(1) ? "" : reader.GetString(1);
        }
    }

Additionally, I took the suggestion of debugging it - I minimalized the code and added one breakpoint at cmd.CommandText = "SELECT * FROM TABLE"; and a second at reader.Dispose(); in order to let the while loop run in order to see how long it takes to go from the first breakpoint to the second.

Program.cs (without Apache Ignite/cache configurations):

class Program
    {
        static void Main(string[] args)
        {

            // Create Connection
            OracleConnection con = new OracleConnection();

            // Create ConnectionString using Builder
            OracleConnectionStringBuilder ocsb = new OracleConnectionStringBuilder();
            ocsb.Password = "PASSWORD";
            ocsb.UserID = "USER";
            ocsb.DataSource = "URL";

            // Connect 
            con.ConnectionString = ocsb.ConnectionString;
            con.Open();
            Console.WriteLine();
            Console.WriteLine(">>> Connection Established");

            // Execute a SQL SELECT
            OracleCommand cmd = con.CreateCommand();
                // Breakpoint #1
            cmd.CommandText = "select * from TABLE";
            OracleDataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                //Table table = new Table();
                //table.SetObject(reader);
            }

            // Clean up
                // Breakpoint #2
            reader.Dispose();
            cmd.Dispose();
            con.Dispose();
        }
    } 

From the diagnostic session, the breakpoint #1 occurred at 2.23s and breakpoint #2 occurred at 2,772.89s - meaning that it took 2,770.66 seconds or ~46 minutes between the two breakpoints.

I was wondering what the reason could be? And also, can this be resolved?

I have referenced

and answers seem dated/unhelpful for this certain usecase.

  • 2
    How many rows does the query return and how much data is that in terms of MB? Are you sure that you are measuring the time for Toad to fetch all the rows? Normally, GUIs fetch the first few rows of the result and display that for you and only bother fetching the rest of the data if you specifically request it (sometimes by scrolling through the results). Have you profiled the .Net code to see where it is actually spending its time to confirm that it is in the database? Do you see different query plans in Oracle? – Justin Cave Dec 07 '20 at 06:11
  • `// Store TABLE.Id, TABLE.Name as key-value pair object` Show us that code please. – mjwills Dec 07 '20 at 06:11
  • 1
    Also, try leaving `// Store TABLE.Id, TABLE.Name as key-value pair object` commented out (i.e. the `while` loop is completely empty). Now put a breakpoint on `cmd.CommandText = "SELECT * FROM TABLE";` and another on `reader.Dispose();` Run to the first breakpoint. Click F5 and measure (with your phone or stopwatch) roughly how many seconds it takes to get to the second breakpoint and share that with us. – mjwills Dec 07 '20 at 06:13
  • Please share a [mcve], not code _similar_ to what you have. – mjwills Dec 07 '20 at 06:16
  • @JustinCave There are 500,000 rows in TABLE and the size is around 300MB. I misspoke about the 250 msecs - that time is for retrieving 500 entries; it takes at _most_ 65 seconds to retrieve all 500,000. – Mangled_Aura_Nada Dec 07 '20 at 17:36
  • @mjwills I took your suggestions and edited my post - the time it took to get from breakpoint #1 to breakpoint #2 was 2,770 secs, roughly 46 mins – Mangled_Aura_Nada Dec 07 '20 at 17:37
  • After you create `reader`, change its `FetchSize` to big value, something like `reader.FetchSize = 10 * 1024 * 1024;` – Ulugbek Umirov Dec 07 '20 at 17:38
  • @UlugbekUmirov I tried your suggestion - it worked! It cut the overall execution time from 50 minutes to 2 minutes! Is there a set back of trying to increase the FetchSize to a higher number? – Mangled_Aura_Nada Dec 07 '20 at 19:20
  • There is no negative effect if you are going to consume all data. By increasing `FetchSize` you increase size of data transferred to you in single round-trip - if you'd want to read only first record and discard all others - that would affect negatively, but that's not your case. – Ulugbek Umirov Dec 07 '20 at 19:52
  • Wow, your TTFB / latency to your DB server must be terrible. – mjwills Dec 07 '20 at 22:18

0 Answers0