‏הצגת רשומות עם תוויות Performance. הצג את כל הרשומות
‏הצגת רשומות עם תוויות Performance. הצג את כל הרשומות

Benchmark in general and hibernate benchmark in more details

 Few weeks ago I was asked about Hibernate overhead compared to using direct SQL/JDBC.
The questioner expected to get a numeric answer, which will help him decide between the two. Unfortunately there is no short answer. During this post I will try to cover benchmark concept in general and Hibernate benchmark in particular.


Benchmark in general:

There is a saying that is attributed to Benjamin Disraeli (1804-1881) :
I will focus on the third kind - statistics. 

Few years ago benchmarks was very popular, but today people realize that test results are affected by dozen of parameters such as JVM flags, the number of cores, the hard disk drive , and others. Also, each framework reaches its best on a specific distinguished scenario when running on a specific environment. Eventually the popularity of benchmarks went down. Once in while I encounter benchmarks which demonstrate results of more than 1000% gap between different frameworks, and then, the gap vanish by only changing a single factor like heap size. Furthermore, some frameworks specialize in complex model, while other, in flat model. The conclusion is that the same test case will not bring the best from all frameworks. For those reasons and others, it’s very easy to create misleading benchmarks.

Should benchmark be the leading factor?

The short answer - No.
The fact that framework A is three times faster than framework B is not a guaranty to get the same results in our application.
There could be couples of reasons for that:
1. The benchmark didn’t use cache and in our application we use in cache.
2. It could be that in our application framework A contributes only one percent of the time, thus, replacing framework A for another that work three times faster will have negligible impact to our application performance.
3. It could be that framework B gains its performance speed by creating lots of objects, thus, in case our application suffers from frequent GC or has limited memory,  integrating framework B in our application instead of framework A will reduce performance.



Summary of the problem so far:

1. There are endless test cases; each of them can lead to different result.
2. Each framework need different configuration in order to get the best of it. Furthermore, different test cases scenarios will need different configurations for given framework in order to get the best of it.
3. Faster benchmark doesn’t mean our application will be faster.
4. Speed is not the only factor.

Benchmark and hibernate:

Hibernate performance can be affected by dozens factors, such as memory, DB; local or remote DB, the model complexity and etc’
Database is ranked as one of the main reasons for bottleneck. Hibernate is working with a Database. This brings Hibernate to be a popular player in application performance discussion.
Most of the time (almost 100%), Hibernate development team gets angry when a new post on hibernate performance pop-up. They respond that the benchmark that was performed was not written well. Examples for that:
Look on Gavin King response there:
“Carl, nobody gets upset about competition, people get upset over FUD benchmarks.

Take it offline, guys.”
The guy who post the above didn’t take hibernate unpleasant response for granted and published an angry post on hibernate performance and unpleasant response in his blog:
“I posted some questions to the Hibernate forum to validate the approach I had taken and I received the rather terse and unhelpful reply “This is called 'A useless micro benchmark' and has been addressed a thousand times.” from a member of the Hibernate team. I did some reading of the Hibernate Performance FAQ and found some interesting statements in there, such as "We claim that Hibernate performs well" and "Many people try to benchmark Hibernate. All public benchmarks we have seen so far had (and most still have) serious flaws.” It almost seems like it is taboo to question Hibernate performance. I don't understand this defensive stance since most developers would recognize that there is a tradeoff between ease of use and performance.”


So, where is the truth - what is the overhead of using Hibernate?

If you read the post so far you should already know that you will not get a simple numeric answer from me. As Explained above, it depends on a many factors.
So how should one decide if to use Hibernate or not?
The simple answer - if its work for others it will probably work for you.
This answer is not a silver bullet because small differences between applications can cause a huge performance impact, however if your application has a mainstream common behavior, like other applications which use Hibernate, then it will probably work for you too.

As a child I did stupid things many times (I didn’t rehabilitate from this habit). When the word came to my dad, that I did something stupid, he used to ask me – “why did you do this?” and I always had the same answer – “I did this because everyone else did”. Then my father used to reply – "what if everyone was jumping off the roof, would you also do did this?”
The analogy is that the fact that everyone uses hibernate is not strong and sufficient case, but this case has some power. If everyone succeeds in using it, then the burden on proving there are problems in Hibernate passes to you. In most cases you will find out that the problems which popped up came from using the framework incorrectly, and not because Hibernate has problems or performance issues.

Stop blathering and give as some numeric answers

Hibernate FAQ states that there is 10% overhead on using this framework:
http://simoes.org/docs/hibernate-2.1/15.html “We claim that Hibernate performs well, in the sense that its performance is limited by the underlying JDBC driver / relational database combination. (Generally the overhead is much less than 10% of the JDBC calls.)”
“Most of the performance problems we have come up against have been solved not by code optimizations, but by adding new functionality. It turns out that the overhead of Hibernate itself, compared to equivalent direct SQL/JDBC, is almost always so small as to be irrelevant. So we concentrate our effort upon producing more efficient SQL/JDBC. The bottleneck is always the database itself.”

However, all over the web you will find people saying they think there is a greater overhead, which means less performance.  The truth is that most of them did not ran any benchmark test. Some, ran benchmark, but did run them well. They did not take into consideration that a good benchmark test should clear the DB cache, warm the JVM and etc’
Following the link to a post about consideration to be taken with JVM level, in order to create a good benchmark:
I chose to cover here three benchmarks.

The Ugly:

The ugly benchmark is so ugly that it caused Gavin King to be angry and even to invest time and publish a post on this benchmark. Why is it ugly?
A company named Software Tree released a new version of their ORM product, JDX. In addition they came equipped with STORM, the Tree Object/Relational Mapping Benchmark Software.
Since this is a commercial product I expect them to invest a minimal time and effort before they publish benchmarks, but they didn’t do that. Instead,  the code they wrote for benchmarking Hibernate was worse than a beginner/new comer to hibernate code.
It worth to look and see why Gavin doesn’t like benchmarks:
“Now, having spent a fair amount of time performance profiling database access technologies, I knew for a fact that these kinds of benchmarks are usually completely misleading. With such small datasets, accessed repeatedly, the database is able to completely cache results in memory; the benchmark never actually involves any real disk access (watch your hard drive while STORM runs). We never get to see what happens once the dataset is too large to fit in memory, or is being updated by another transaction. We never get to see what happens with the database is under load. In fact, this benchmark involves no concurrency at all! We never get to see any joins or any of those other things that happen in realistic use cases. Furthermore, these kinds of benchmarks are often run against a local database, which gives results that are absolutely meaningless once the database is installed on a physically separate machine. What this means is that
1. Any overhead added by the ORM is massively exaggerated compared to production scenarios
2. We cannot observe how the system scales

The interesting part of ORM performance comes when you start to investigate caching and especially the flexibility of association fetching strategies. In a nontrivial object model with associations, it is usually association fetching that limits performance. ORM tools must provide flexible ways of choosing between Lazy fetching plus process-level caching and
Eager fetching using outer joins.”

Gavin take their benchmark and play a little with it.
They started with 2 minute to Hibernate and 12 sec to JDX.
After changing some basic hibernate usage, the time has been reduced to 21 sec.
JDX doesn’t use in prepared statement which means that if you run small tests the benefit can be better. Gavin plays a little with the test and in some cases Hibernate wins JDX and in another the results are the same.
The above post is recommended for reading.

The Interesting:

Another interesting benchmark came from Italy.
Why is interesting? Because, unlike other benchmarks that compare the time that take for each tool to do X , this one compares the productivity of the frameworks for a given time (30 minutes).In additional unlike others that compare flat simple single class in almost empty DB here is uses  MySql sample database. The employee sample database e was developed by Patrick Crews and Giuseppe Maxia and provides a combination of a large base of data (approximately 160MB) spread over six separate tables and consisting of 4 million records in total. This benchmark comparea different JPA implementations, but unfortunately it didn’t add JDBC to this benchmark.
Results
These were the results of the tests per JPA implementation library. Notice that the time frame is fixed; 30 minutes for running each framework, and here is what each framework succeed to do in 30 minutes.
Number of queries+inserts executed
Number of queries executed
Number of inserts executed
Max mem occupied during the test(Mb)
Mem occupied after the test(Mb)
OpenJPA
3928
3530
398
96
61
Hibernate
12687
3080
9607
130
79
Toplink Essentials
5720
3740
1980
55
25
Eclipselink
5874
3735
2139
57
25

Red represent bad.
Bold represent top result.
Ps – Hibernate consume large memory but it did more work than others, so it’s reasonable.
First we need to grateful for the investment, but still this benchmark suffers from several benchmarks issues. It cleans the DB and avoid from basic problems, but have other issues that need to take into consideration when you do benchmark.  The guy did that benchmark gets a lot of response, few of them deal with the way he did the benchmark. He also publishes the reference in server side and gets a lot of response there.
Its worth to take a look on   John Stecher interesting comment before jumping to conclusions:
http://www.theserverside.com/news/thread.tss?thread_id=53142

.Net and Java

This benchmark is for both .Net and Java include Linq and Hibernate
The test suite consists of:
A simple query to return 1000 records.
A simple query to return 1 record.
A simple query to insert 1 record

His Conclusion:
“These tests demonstrate raw crunching speed of returning row data, if you are using complex queries where you have slow result times (greater than 10ms) from the database, all of these timings for the connection layer become negligible.
One solution does not fit all, as with most programming practices. Use your best judgment and try to keep your code simple, but not so simple that it creates an efficiency bottleneck. Real world is somewhere between the 1000 query result and the 1 query result set. Use your discursion on where your code resides within these bounds. These results lend me to emphasize that you use object oriented best practices around all your code, but if necessary on pure raw atomic crunching queries, use your judgment on when to jump the fence to the raw crunching power of ADO.NET or JDBC. Make sure your code is well commented.
JavaHibernateSQL/NHibernateToSQL(.NET) and compiled Linq queries appears to perform approximately 2 times slower than raw JDBC/ADO.NET at worst. Overhead as expected with an ORM”

But, after looking at his code I was disappointed that many benchmark considerations like cache, DB size … as explain above didn’t take into consideration here.

My favorite (which still need a lot of improvements):

This benchmark was published by PolePostion. PolePosition is a benchmark test suite to compare database engines and object-relational mapping technology. As of today it is by no means complete. Database vendors and open source database project participants are invited to improve the test implementations and to contribute further disciplines ("Circuits"). The PolePosition framework source code enable implementing new tests quickly and help measuring time, and outputs the results as number series and graphic visualizations.
They have some test suite for example – Barcelona:
Writes, reads, queries and deletes objects with a 5 level inheritance structure

The read results:
t [time in ms]
selects:100
objects:1000
selects:100
objects:3000
selects:100
objects:10000
selects:100
objects:30000
150
433
1317
4068
574
1300
4255
12377
331
990
3368
10530
19
43
162
483


But, The tests were written by people that admit they are not familiar with Hibernate also a lot of consideration in benchmarks as explain above didn’t take into consideration.
Any way – they did a great work and invested in code. Still they need to do some additional work there in order to be an excellent reference
This benchmark was published on Hibernate forum and gets the usual
Hibernate team answer:
“Since this "benchmark" has been written by someone who admits that he doesn't know anything about Hibernate, you won't get much usable information out of it. This particular thing has been debunked internally by a member of our team in 15 minutes - with now Hibernate being "100x faster". There is just no value in publishing this, since it would a) encourage others to waste our time again with similar stuff and b) cost more of our time than it is worth.

We get many benchmarks like this from competing vendors (note that this is particular benchmark very likely encouraged and/or sponsored by an object database vendor) and we don't have the time to debunk them all. We encourage you to create your own benchmarks if you want objective results. Some trivial micro-benchmarks that show the real JDBC overhead for unrealistic non-concurrent data access are available in the Hibernate distribution, as the "ant perftest" target.”

Overhead – is it the best tool for compare?
Look at the benchmark above, if you build your conclusion on the HSQLDB results you can come to a misleading conclusion that Hibernate overhead is 700% compared to JDBC, because as you can see above that HSQLDB JDBC time measurement is 19 and Hibernate time is 150. The overhead as a single metric is misleading in this case, because when deal with in memory DB or local DB or cached DB or small tables or simple model, any overhead added by the ORM is massively exaggerated compared to production scenarios. So overhead is not always the best tool.

What about Hibernate own tests?

Hibernate have a minimal and simple performance test, located under Hibernate source:
Hibernate-distribution-3.5.1-Final\project\testsuite\src\test\perf\org\Hibernate\test\perf\NewerPerformanceTest.java.
The model is simple and the DB doesn’t contain a lot of records, so the tests suffer from exaggeration of the ORM part. Even so I run them on local MySql and the results was 100% overhead. On a production DB (contention on the DB, complex model, remote…) the overhead will be much smaller, but I didn’t test it. In a post I published on Hibernate forum I encouraged Hibernate team to publish their tests and to have more performance visibility. When examining Hibernate we don’t need to focus on overhead only, we need to examine how much time it add to our specific application use cases. When you evaluate you should take into consideration – first and second level cache, lazy loading, merge algorism, optimistic lock handling and etc which can significantly reduce performance impact. In addition, don’t forget the Pareto rule. For the 20% hard problems that don’t get a full solution by Hibernate you can always fall back to direct JDBC, so when you make your considerations it’s very important to focus on the 80%.

Conclusions:

1.       Fact#1 - Hibernate works. Fact#2 –on average enterprise application it can work with good performance. Those two facts get an approval by thousand applications, which are shipped with Hibernate.
2.       Don’t believe to any benchmark that you see on the internet.
3.       Try to create your own benchmark based on your application needs, based on your application architecture (remote or local db/cache policy…).Run the benchmark on semi production environment.
4.       When you create a benchmark, focus on the 80%. Test the average scenario. The other 20% can get an alternative solution. Don’t chose a solution that cover all the 100% but required a lot of investment and has a curve learn.
5.       Overhead can be misleading. The real factor is the fixed time that adds to the use case.
6.       Hibernate is not suited to all applications. There are lots of alternatives out there like IBatis, Spring JDBC…
7.       Creating a good benchmark is not easy. Many factors are involved
8.       It will be great if hibernate team will improve their performance visibility. Cooperation with “PolePostion” is required.

Thanks to Yair Fine for the English review,I invented a new language when i wrote it and thank to Yair help the post now can read by brave English reader and not limited only to "Avihai" speakers, however all syntax mistake belong to me and Yair didnt have time to cover all.



Hibernate - Don't forget the first level cache

A lot of developers ignore or forget about hibernate first level cache.
Hibernate firs level cache is part of the session and not visible to other sessions.
The first level cache cannot be disable and its not optional like the second level cache.
In the first level cache hibernate use in order to store  attached entities. This is in order to:
1. Performance - avoid db hit for re fetch of the same entity more than one time during the transaction.

2. Avoid "shadow object" in order to track on attache entities changes. Explain:
 Well imagine this code:
c1 = session.get(Customer.class, 42);
c2 = session.get(Customer.class, 42);
(note: the get could be replaced with any other kind of query, hql, criteria, *lazy navigation* etc.)

If hibernate doesn't store the attached entities in the first level cache than we will have two different instance of the same customer row. So,
assertSame(c1, c2); should fail but
assertEqual(c1, c2); would actually pass (if you have a proper equal/hashcode implementation)

What wrong with this?
Changing c1 attributes would not affect c2, so hibernate doesn't allow to have more than one instance of the same entity attached to the session.Hibernate do this by using a central place to control on all attached entities. this placed is called- first level cache. Any get  (actually not any . We can bypass it like using statelesession for example ) and update on entity
If Hibernate (or any other JPA implementation) would not do this you would have these “shadow objects” all over the place and the developer will need to manually keep track and ensure that you only use *one* of these objects.


So, this is a build in hibernate mechanism that cannot be turn off- why should i care about it?
Good question (this is the reason i wrote it :) ).
Answer:
A lot of developers complaints on hibernate come-up from not understanding  hibernate mechanism.
In the continue i will a link to 2 posts that talk about problems in hibernate . which can be solved by right use in the hibernate framework.

The main reason that you should be aware to the first level cache is - performance.
Attach entity has a cost:
Cost of using proxy, cost of tracking (hibernate need to keep track on the object state), keep of synchronize  - in flush hibernate need to check if it should synchronize the object to the db. the check and the write to the db cost a lot and in most cases they are not necessary, memory - the object leave in the memory even if we are not going to use it any more.

In the following post avoiding-caching-to-improve-hibernate-performance the developer describe a common use case scenario. he has a XML which each element in the XML is a combination of few hibernate entities. he read element from the XML , do some db query for load references entities, look up data, validations and etc create entities based on the XML element and save it to the db. Since he want to get a good performance by avoid loading data from the db for each XML element, he didn't open hibernate session for each XML element.
He was sure that in this way he can utilize the hibernate first level cache and avoid hit the db for each element.
But, he observed that the performance decrease and the processing time required per input record in the data set increased linearly.

The reason - first level cache. The first level cache is get bigger and bigger during the processing time and this has major impact on hibernate performance. Most of the time is spent around hibernate synchronization mechanism (flush).

So - what is the lesson?
You should always concern about your first level cache. If you need the objects only once in the session load them in minimal scope by stateless session by this hibernate will not need to produce proxies, keep track on the objects and they will be free to be collected by the GC.
Another options:
use in readonly mode for read only entities (there are additional options to define read-only).
Define entities as immutable were optional.
Clear the first level cache from unnecessary entities.

How to clear the first level cache?
JPA API doesn't support in clear specific instances. It support only in clear all .Hibernate API allow you to clear specific instances . If you did changes to the instances make sure that you call to flush before clear . The entities become detached after clear , which mean hibernate will not keep track on them and  their state will not be synchronized with the db.

Solving by design - another design approach like use in process-context for the read-only data and session for each element processing can also solve the problem and in this way have short live session, short db transactions, avoid trigger flush during the process.

further reading  :

Hibernate - should i fetch and how?

In  the top application bottlenecks we find issues regarding to the database area. When dealing with DB we need to plan well - the access and the fetching scope.

Since DB is the bottleneck hibernate, as a third party that work against the database, has a major impact on the application performance.
Lot of people look for a mystery configuration flag that will boost their "hibernate performance". I am sorry to disappoint you there isn't such flag. I search on all hibernate source code for an attribute name - "boost performance" and didn't find it. There are some hibernate configuration that can affect the application performance like batch size and etc , but don't hang up your hopes on those configurations.
If there is performance problem- they mostly hide in your application and not in hibernate global configuration.

In most cases either you load too much information or your current fetch plan is not the best choice.
Hibernate have some attributes which control on the data fetching.

The main two are:
1. Lazy - true/false
2. Fetch strategy - select,subselect,batch,join

The lazy - control on -"when" should I fetch the association now!!!! Immediately, with the association owner.
The fetch strategy control on "how"- should i load them in join with the owning entity? Should I load them in second select...
Obviously the attribute has some overlap. If you chose in fetch strategy join this means that you need to load them with the owning entity (the answer to the "when" is now).
So if the fetching is too slow - check the fetching plan - did you load too much information, did you have many db access? Should I change the plan?
Developers love to thing on magic solution- one solution for all problems. we told a lot of time that join is the best solution since it minimize the db access - so again sorry to disappoint you the answer is not- join is not the best answer for all situations (i will expand on this in the near future).

So now you need some details. as a java programmer I believe in reuse so I will give an excellent references.
http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/
http://www.javalobby.org/java/forums/m91885142.html
http://community.jboss.org/wiki/AShortPrimerOnFetchingStrategies

Clean your temp directory

A lot of process (cache , build tools, generators) use the temp directory and dont clean it.
A big temp directory will make the process that use it much much slower.
For example build of c# project was 3 time faster after i clean the temp direcoty.

If you dont know where is it just write in the command line %temp%

Premature optimization is the root of all evil

אני אוהב משפטי "root of evil". צביעה של עולם בשחור ולבן מקלה על החיים.למרבה הצער- העולם הוא לא באמת שחור ולבן.אפילו הביטוי הכול כך החלטי :

"premature optimization is the root of all evil"
שנהגה על ידי Donald Knuth ומשמעו:

"Premature optimization" is a phrase used to describe a situation where a programmer lets performance considerations affect the design of a piece of code. This can result in a design that is not as clean as it could have been or code that is incorrect, because the code is complicated by the optimization and the programmer is distracted by optimizing."
אינו כה חד מבחינת המקורות שלו.הציטוט הוא חלקי ביותר ולא משקף במאה אחוז את הקונטקסט השלם.הציטוט הינו מתוך מאמר שפורסם ב-1974 על ידי KNUTH והמשפט המלא הוא:

"The conventional wisdom shared by many of today's software engineers calls for ignoring efficiency in the small; but I believe this is simply an overreaction to the abuses they see being practiced by pennywise-
and-pound-foolish programmers, who can't debug or maintain their "optimized" programs. In established engineering disciplines a 12% improvement, easily obtained, is never considered marginal; and I believe the same viewpoint should prevail in software engineering. Of course I wouldn't bother making such optimizations on a oneshot job, but when it's a question of preparing quality programs, I don't want to restrict myself to tools that deny me such efficiencies.
There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

כמו כן 12 שנים אחר כך בראיון שנתן עידן KNUTH  את הביטוי.אך היסטוריה היא לא מטרתנו כאן.
גם החלטיות היא לא מטרתנו כאן, אבל כדי לא לפתוח כל מיני סוגריים ותתי סוגריים והסתייגויות, אנסה להתייחס לרעיון הכללי וכל דבר ספציפי כמובן מצריך את ההתייחסות שלו.
אופטימיזציה של מערכת נעשית בשלבים שונים של המערכת:
1.      שלב הארכיטקטורה.
2.      בחירת טכנולוגיות
3.      Height level design
4.      Low level design
5.      Implementation
6.      Bug fixes
בכל שלב יש להשקיע כמות שונה של זמן לגבי אופטימיזציה.
בניית ארכיטקטורה שגויה היא תקלה שקשה להתגבר עליה ולכן מין הסתם כמות המחקר לגבי אופטימיזציה שצריך להשקיע בשלב הזה גדולה הרבה יותר משלב המימוש.

יש כאלה שעל מנת להבחין בהתייחסות לשלבים השונים ממקדים את הציטוט לעיל לכדי הציטוט הבא:

"premature optimization is the root of all evil  micro".

הסבר שאהבתי שמתייחס לציטוט המקורי הוא:
in the absence of measured performance issues you shouldn't optimize becuase you think you will get a performance gain. There are obvious optimizations (like not doing string concatenation inside a tight loop) but anything that isn't a trivially clear optimization should be avoided until it can be measured.
בואו ננסה לצלול לציטוט מתוך דוגמה אמיתית:
Java formatter הוא אובייקט " יקר " ( מה זה יקר? – יקר יחסית לאוביטים אחרים ) ואינו thread safe, לכן מתכנת החליט שהוא יצור – ThreadLocalFormat כדי לעטוף את ה- formatter .
אם נריץ TEST שבודק מהו יקר? נקבל במחשב ממוצע יצירה של 200,000 אוביטים בשנייה.
זה מתכנת שעשה premature . נכון, הוא חסך זמן מחשב, אך האם הוא בכלל היה צריך לחסוך זמן מחשב? האם ב- USE CASE  הספציפי שלו זה מה שקריטי?
זוהי דוגמה שלפני שעשית over design למקום שיכל להיות פשוט.מערכת תוכנה היא מערכת מסובכת מעצם טיבעה. אין טעם להוסיף סיבוך נוסף היכן שלא צריך. במידה ואינך יודע בוודאות כי כתיבה מסוימת עלולה לעלות ב- performance  יקר (אם אינך יודע בדוק לפני) אל תכניס אופטימיזציות. הם רק יסבכו אותך אחר כך בתחזוקה וב- debug . ראיתי מתכנתים שעבדו ימים על גבי ימים כדי לבצע סוג מסויים של פילטור נתונים מתוך רשימה בכמה שפחות מעברים על הרשימה. הם השקיעו ימים כדי להגיע לאלגוריתמים הכי טוב וכזה הגיע אלי השאלה הראשונה שלי הייתה למה לא לעבור על הרשימה 6 פעמים ולא 2 כפי שתכננתם אבל בצורת קוד יותר ברורה?
התשובה שלהם הייתה שמעבר על הרשימה 6 פעמים זה בזבוז שכן בצורה חכמה ניתן להוציא את המידע על ידי שימוש בכל מיני טריקים ורק ורסיות בפעמיים בלבד.
כששאלתי מה ה- impact של לעבור עליה 6 פעמים ולא 2 (נניח כרגע את הרק ורסיות בצד) התשובה הייתה – מדובר בפי 3 זמן.
תשובה זאת אינה מספקת, שכן פי X זמן אינו מדד לכלום. מה אם אגיד לכם שאני יכול לייעל חלק מסוים בתוכנה שלכם שיעבור במאית מהזמן הקודם או שתעדיפו שאייעל חלק אחר שיעבור ב-99 אחוז מהזמן הקודם? אני בטוח שכולנו לא נסכים להצעה כזאת בצורה עיוורת ונשאל מה ה- IMAPCT על התוכנה כולה. בכמה זמן יורד אותו USE CASE ? בכמה יורד חתימת הזיכרון ? בכמה יורד בעיות של contentions ? ...
פי X אינו מדד לכלום.
כנראה שהאוניברסיטה (קורסים לחישוביות ואלגוריתמים ) השפיעו רבות על כולנו וההסתכלות של רבים על עולם התוכנה היא סביב חסם ה- O (http://he.wikipedia.org/wiki/סיבוכיות). כמעט בכל ראיון עבודה ישאלו את המתכנת שאלת סיבוביות , בכמה מעברים מינימאליים תוכל לעשות זאת? בפוסט הבא מתוארת סוג כזאת של שאלה http://j2ee-now.blogspot.com/2007/12/google-interview-questions-part-1.html כפי שנשאלת בראיונות של גוגל. תגובה מעניינת שיש שם היא תגובתו של Riccardo:
That's the typical kind of problem you forget how to solve when you work for years using high level frameworks (in any language); in my career I have never seen a case where a problem of this complexity had to be solved.
מניסיוני ראיתי הרבה מקרים של התעסקות באופטימיזציה באופן שהוא Premature כלומר נטול הוכחות לכך שיש כאן בכלל צורך של אופטמיזיציה. הטענות של המתכנתים הן בסגנון – זה יותר מהר פי X, מה אם ברשימה יהיו מיליון רשומות ? , מה אם יהיו מיליון משתמשים שירצו את אותו מידע... כתיבה נכונה של קוד בצורה של בלוקים שניתנים בקלות לפירוק והרכבה אחרת (Refactor) נותנת לכם את היכולות להתמודד עם הבעיות במציאות ולא בתאוריה. אין צורך לתכנן אלגוריתמים יעיל על סמך כך שברשימה יהיו מיליון רשומות. יש צורך לתכנן אותו על סמך כמה שיש בפועל ולא בתיאוריה.
שימו כל הזמן מול עיניכם שאנו מדברים היום במעבדים שמצבעים מיליארדי פעולות בשנייה. מעבר של 5 או 6  פעמים או אפילו 10 על רשימה לא יהיה מה שישנה להם. לכן אל תזדרזו לעשות אופטימיזציה ללא שאבחנתם שיש בעיות או ברור לכם שיש בעיות (premature).
ובכלל כדאי לבחון מחדש כל מיני דיעות קדומות שלנו לגבי ביצועים. אמונות שנשענות על בסיס בעיות שהיו בעבר ולא קיימות כבר היום לדוגמה – שאלו את עצמכם את אותה שאלה שנשאלתם בראיונות לגבי ביצועים של HashTable  ?
מרבית מאמרי ה- Performance וטיפים לגבי Micro Performance נעשו סביב JVM ישנים. הספר האחרון שעסק בתחום של MIcro Performance יצא במהדורה שנייה עבור JDK 1.4 .  מאז נעשה שיפור דרמטי בנושאי ביצועים כך שהרבה טיפים לא רלוונטים עוד.
ה- Optimizer של ה- JVM מסוגל היום לניסים בעיקר בזכות JIT עד כדי כך שהביצועים יכולים לעלות על ביצועי קוד שנכתב ב- C. שיפורי ביצועים בכל האזורים החל מ- IO וכלה בנושאי Concuurency הביאו לשיפור של לפעמים פי כמה אלפים יותר מהיר בין JDK 1 לבין הגירסה הנוכחית. יש לשים לב שכדי לחוות חלק מהאופטימיזציות יש " לחמם " את ה- JVM.  כאשר אתם בודקים ביצועים קחו זאת בחשבון.ניתן לראות דוגמה בפוסט הבא  - http://avihai-java.blogspot.com/2010/05/arraylist-vs-array-as-sample-to.html
לפוסט יותר מפורט על JIT:
http://www.ibm.com/developerworks/java/library/j-jtp12214/

כדאי לקרוא את הפוסט הבא שמדגים שיקולים רבים שעלינו לשקול מבחינת בדיקת ביצועים נכונה:
http://www.ibm.com/developerworks/java/library/j-benchmark1.html



Concurrent transaction locking

לאור כמה שיחות עם אנשים אני מתכוון לסקור כאן בקצרה את עניין נעילות ה- DB.
אני לא מדבר על נעילות יזומות ( מפורשות ) כאשר ה – CLIENT מבקש נעילה על אזורים מסוימים ב- DATABASE ( כל VENDOR  מאפשר SYNTAX שונה וכן נעילות שונות ).
אלא אני מדבר על נעילות שה – DATABASE  עושה בעצמו על מנת לשמור על עקביות של נתונים, על מנת לנהל נתונים...

בואו ניקח את ה – scenario  הבא:
Client B (Isolation level = read committed) מנסה לקרוא נתונים מטבלה בזמן ש-  client A נמצא בתוך טרנזקציה ועושה שינויים על הטבלה הזאת. האם client B  ינעל ויחכה עד ש- client A  יסיים את הטרנזקציה?

לאחרונה שמעתי מיותר מדי אנשים את התשובה – נעילה, כלומר client B ינעל ולא יוכל לבצע את השאילתא עד ש- clinet B לא יגמור את הטרנזקציה.

ובכן – התשובה היא מאכזבת – תלוי.
במה זה תלוי – זה תלוי במימוש הטרנזקציות הפנימי של אותו db vendor.
במידה ואותו vendor   לא מנהל גרסאות מקבילות של אותה רשומה , אז כדי להבטיח read committed  הוא יצטרך לנעול את הטבלה או האזור לקריאה עד שלא יתבצע commit  על הנתונים.

ניהול של גרסאות מקבילות של אותה רשומה על מנת למנוע נעילה של הרשומה לקריאה במקביל לשינוי הוא משהו מאוד בסיסי ביכולות שאנחנו מצפים מה – database  שלנו.
אותי בתור client  לא צריך לעניין שיש clients  אחרים שמשנים את הרשומה וטרם ביצעו commit. ( במידה ואני ב- isolation read committed ).

ל – MSSQL לקח זמן להבין את זה והם הצטרפו די מאוחר לתמיכה בגרסאות שונות לאותה רשומה וכיום הם תומכים ב –row version.
התמיכה הזאת נעשית דרך הגדרת הDB בתור SNAPSHOT.והתמיכה החלה החל מ-2005.
SQL Server 2005 introduces a new snapshot isolation level to enhance concurrency for OLTP applications. In earlier versions of SQL Server, concurrency was based solely on locking, which caused blocking and deadlocking problems for some applications. Snapshot isolation, by contrast, depends on enhancements to row versioning and is intended to improve performance by avoiding reader-writer blocking scenarios.

בואו נדגים את המקרה שתארנו על שני DB שונים- mysql, mssql (2005)

יצירת הטבלה :
MySql:
create table TestLock)
       IK INT auto_increment NOT NULL,
       MyName NVARCHAR(200) not null,
       primary key (IK)
)type=innodb;
insert into TestLock(MyName) values (1);
insert into TestLock(MyName) values (2);
insert into TestLock(MyName) values (3);
insert into TestLock(MyName) values (4);

Client A:
00:
Begin;
insert into TestLock(MyName) values (5);

//Not committed!!!

Client b:
01:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
Begin;
Select * from TestLock;

// No problem – we get committed data – no lock

Mssql :
createtable TestLock(
       IK INT IDENTITY NOT NULL,
       MyName NVARCHAR(200) not null,
       primary key (IK)
    )

insert into TestLock(MyName) values (1);
insert into TestLock(MyName) values (2);
insert into TestLock(MyName) values (3);
insert into TestLock(MyName) values (4);

we will distinguish between two db types – snapshot on and off.

Snapshot off:
Client A:
00:
set transaction isolation level  read committed  set implicit_transactions off 
go
set implicit_transactions on 
go
insert into TestLock(MyName) values (5);

//Not committed!!!

Client b:
01:
set transaction isolation level  read committed  set implicit_transactions off 
go
set implicit_transactions on 
go
Select * from TestLock;
//Lock – because mssql lock the last rows of the table since it need to add data to them.
Mssql doesn't lock the table. It lock the area that it need (it depend on the block size … ), so if we limit the select query range to range that not include the lock area the read will not be blocked.
For example:
Select * from testlock where IK < 4
//No lock !!!!
If we turn on the snapshot (in the db and in the transaction committed_snapshot) – No lock needed, so select all will work even there is a parallel uncommitted transaction that insert data to the table.