Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Great performance drop #836

Closed
pazicb opened this issue Dec 15, 2017 · 26 comments
Closed

Great performance drop #836

pazicb opened this issue Dec 15, 2017 · 26 comments

Comments

@pazicb
Copy link

pazicb commented Dec 15, 2017

Hello,
I have a problem, see the example below. In version 4.0.0-beta2 this is done in 500 ms.
In version 4.0 this is done in 75000 ms. Why has dramatically reduced performance?
Thank you for answer.

using (var db = new LiteDatabase(@"MyData.db"))
{
    var customers = db.GetCollection<Customer>("customers");
    for (int i = 0; i < 1000; i++)
    {
        var customer = new Customer
        {
            Name = "John Doe",
            Phones = new string[] { "8000-0000", "9000-0000" },
            IsActive = true
        };
        customers.Insert(customer);
    }
}
@mbdavid
Copy link
Collaborator

mbdavid commented Dec 15, 2017

Hi @pazicb, I don't know about this different between beta and final, but using this way is normal this large time consume. Each insert will write on disk. Try use customer.Insert(IEnumerable<T> docs) like this (you will see a huge difference in time.

In this example I got 123ms to insert 1000 documents. Here my full test:

namespace LiteDB.Demo
{
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string[] Phones { get; set; }
        public bool IsActive { get; set; }
    }

    class ProgramCustomer
    {
        static void Main(string[] args)
        {
            var timer = new Stopwatch();

            File.Delete(@"MyData.db");

            timer.Start();

            using (var db = new LiteDatabase(@"MyData.db"))
            {
                var customers = db.GetCollection<Customer>("customers");

                customers.Insert(GetCustomers());
            }

            timer.Stop();

            Console.WriteLine("Done in {0}ms", timer.ElapsedMilliseconds);
            Console.WriteLine("End");
            Console.ReadKey();
        }

        public static IEnumerable<Customer> GetCustomers()
        {
            for (int i = 0; i < 1000; i++)
            {
                yield return new Customer
                {
                    Name = "John Doe",
                    Phones = new string[] { "8000-0000", "9000-0000" },
                    IsActive = true
                };
            }
        }
    }
}

I'm testing in FindSort branch (that will be 4.1) that I'm working.

@pazicb
Copy link
Author

pazicb commented Dec 15, 2017

Thank you, I understand your example. I just do not know why the writing speed dropped 150 times. The speed of 13 records per second is very small even when I write to disk. When do you release version 4.1?

@pazicb
Copy link
Author

pazicb commented Dec 16, 2017

In version litedb 4.0 my example uses 95% of disk performance for 75,000 ms. For versions 4.0 beta2 and below, the disk usage is minimal.

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 16, 2017

Hi @pazicb, using v4 from nuget I got this times:

Insert IEnumerable done in 106ms
Insert one-by-one done in 996ms

Here my example:

https://gist.github.com/mbdavid/d62683b9752f7d693a13cfd00a2a2ee6

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 16, 2017

If disable journal file, time drop to: @"filename=MyData.db;journal=false"

Insert IEnumerable done in 105ms
Insert one-by-one done in 711ms

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 16, 2017

Now, if I increase to 10.000 custumers:

(journal=true)

Insert IEnumerable done in 279ms
Insert one-by-one done in 9915ms

(journal=false)
Insert IEnumerable done in 274ms
Insert one-by-one done in 6311ms

I'm running in dell notebook: Windows 10 + I7 - 7500U CPU @ 2.70GHz - 2.9Ghz + 16Gb RAM + SSD disk

@pazicb
Copy link
Author

pazicb commented Dec 16, 2017

Thank you so much. I have very similar times with 4.0 beta 2. When I download version 4.0 release, I get this:
Insert IEnumerable done in 150ms
Insert one-by-one done in 75000ms
Maybe you're using a newer version.
Can you send me the dll you are testing with?

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 16, 2017

Hi @pazicb, here full project solution with dll included. I used nuget to get this 4.0.0

TestLitePerformance.zip

@pazicb
Copy link
Author

pazicb commented Dec 16, 2017

Thank you. LiteDb .NET 3.5 works correctly. NET 4.0 has the above-described problem.

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 16, 2017

Hi @pazicb, can you upload your zip project to test here?

@pazicb
Copy link
Author

pazicb commented Dec 16, 2017

I'm testing your code.
test1.zip

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 16, 2017

Hi @pazicb, I'm still getting same results with your code: 660ms

image

@pazicb
Copy link
Author

pazicb commented Dec 17, 2017

Hello, don't you see any differences between using NET 3.5 and NET 4.0.? I tested it on 5 computers and there was always a big difference. Can you use a disk other than SSD for testing? E.g. Flash disk.

@Otw-cz
Copy link

Otw-cz commented Dec 18, 2017

This caught my attention, just curious - I quickly tested "test1.zip" project using NET 3.5 and NET 4.5 on RAM disk (almost same performance) and standard HDD and there is 10 times difference between NET 3.5 and NET 4.5 (4.5 being ~10x slower on standard HDD than NET 3.5) (3241 vs 327)

For project: TestLitePerformance.zip (Standard HDD)
NET 3.5 (LiteDB v4.1)
Insert IEnumerable done in 370ms
Insert one-by-one done in 723ms
NET 4.5 (LiteDB v4.1)
Insert IEnumerable done in 247ms
Insert one-by-one done in 4686ms

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 18, 2017

Hi @Otw-cz, I didn't test yet on standard HDD because I don't have. I will mount an Azure VM for that.

There are, in code, few differences between LiteDB for NET35 e NET40. And this difference is only about serialization way (in NET35 uses Reflection and NET40 use Expression - which are faster). About disk read/write/lock, there is no changes in code.

You test in RAM disk not using MemoryStrem() initializer, right? This is a complete different way to read/write access. Much more simple with no locks...

@Otw-cz
Copy link

Otw-cz commented Dec 18, 2017

I used RAM disk aka sotware emulated "drive" in RAM memory, sice I don't have SSD :-) (not MemoryStream) (CPU i5-3230m)
For project: TestLitePerformance.zip (RAM disk: 40MB/s for 4kB writing)
NET 3.5 (LiteDB v4.1)
Insert IEnumerable done in 357ms
Insert one-by-one done in 731ms
NET 4.5 (LiteDB v4.1)
Insert IEnumerable done in 237ms
Insert one-by-one done in 598ms

(May be Framework issue? It looks like it does significantly more disk I/O under NET > 3.5 - which does matter on standard HDD, but not on SSD/RAM)

@pazicb
Copy link
Author

pazicb commented Dec 18, 2017

Hello, it looks like SSD and RAM are all right. Every HDD I tested had a problem. The worst result was a 150x slowdown.

@pazicb
Copy link
Author

pazicb commented Dec 20, 2017

Hello, here's a note. The problem occurred in version 4.0. Version 4.0 beta 2 is fine, just like version 3.5.

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 20, 2017

Hi @pazicb, I was checking changes between this versions. I think here can be the problem:

// v4.x
return new FileStream(path, mode, access, share, 
    BasePage.PAGE_SIZE,
    System.IO.FileOptions.RandomAccess);

// v3.x
return new FileStream(path, mode, access, share, 
    BasePage.PAGE_SIZE);

https://github.com/mbdavid/LiteDB/blob/master/LiteDB/Engine/Disks/FileDiskService.cs#L315

Can you remove this System.IO.FileOptions.RandomAccess option and try run again? I still with problems in create Azure VM in my account.

@pazicb
Copy link
Author

pazicb commented Dec 20, 2017

Hello, unfortunately this change did not help. Try the Flash Drive for testing.

@pazicb
Copy link
Author

pazicb commented Dec 20, 2017

Hi, the error is probably causing _stream.Flush(true).

public void Flush()
{
_log.Write(Logger.DISK, "flush data from memory to disk");

#if HAVE_FLUSH_DISK
_stream.Flush(true);
#else
_stream.Flush();
#endif
}

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 20, 2017

hummm... that's make all sense... because in beta, there is no #if HAVE_FLUSH_DISK conditional... only #NETSTANDARD variable (so, in NET35 and NET40 uses _stream.Flush();. In final LiteDB v4, NET35 do not have flush(true), only flush().

Did you test in HDD removing this true parameter?

@Otw-cz
Copy link

Otw-cz commented Dec 20, 2017

I did test on HDD removing the "true" parameter and this seems to be the "issue" - at least TEST times are now on par with RAM drive.
File.Options: RandomAccess
Insert IEnumerable done in 233ms
Insert one-by-one done in 541ms

The question remains - I'm no expert but I guess without "true" it's not being written to the file at that moment (stays in disk cache)?

@mbdavid
Copy link
Collaborator

mbdavid commented Dec 20, 2017

@Otw-cz, using this true parameter, flush operation occurs immediately and all buffer are write into disk. I didn't know that are too much impact in HDD disks (because SSD has no difference).

@pazicb
Copy link
Author

pazicb commented Dec 20, 2017

mbdavid added a commit that referenced this issue Dec 22, 2017
@lbnascimento
Copy link
Contributor

Hi! With the objective of organizing our issues, we are closing old unsolved issues. Please check the latest version of LiteDB and open a new issue if your problem/question/suggestion still applies. Thanks!

github-actions bot pushed a commit to Reddevildragg-UPM-Forks/LiteDB that referenced this issue Nov 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants