I'm new to nHibernate and am having some really slow results from a simple select query. Maybe I'm missing something obvious. The situation as follow:
I am using fluent nHibernate.
I am querying an oracle database (10g), I am trying to return a person object.
It's taking around 16 seconds per record!
Here's my fluent nHibernate code:
public class Person
{
public virtual string PersonId { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Schema("MyTestDB");
Table("Person");
Id(i => i.PersonId);
Map(i => i.FirstName);
Map(i => i.LastName);
}
}
Here is the code that is suppose to retrieve the actual data:
var sessionFactory = Fluently.Configure().Database(OracleClientConfiguration.Oracle10.ConnectionString(#"User Id=tester;Password=tester99!;Data Source=MyTestDB;").ShowSql()).Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())).BuildSessionFactory();
using (var session = sessionFactory.OpenSession())
{
using (session.BeginTransaction())
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var person = session.QueryOver<Person>()
.Where(p => p.PersonId == "1").SingleOrDefault();
stopWatch.Stop();
var ts = stopWatch.Elapsed;
var time = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds/10);
Console.WriteLine("Retrieved object: Person, Id: {0}, First Name: {1}, Last Name: {2} in [{3}]", person.PersonId, person.FirstName, person.LastName, time);
}
}
The PersonId column is indexed and is the primary key.
My attempts to figure this out so far has been to run the same sql generated by nHibernate with ADO.Net. The query ran extremely fast (the stopwatch gets a elapsed time of 0).
Using plsql developer to run the same query on the database gave the same fast results. This suggests to me think it is not the query nor the database.
How can I debug this further? Will nHibernate profiler help with this (I don't have this available to me at the moment)?
Any ideas guys?
Firstly, you should try capturing a few more points in time throughout your programs execution. You've assumed that it's the NHibernate component, but without more data-points that's going to be hard to prove, especially when your initial test comes back with 0.
Secondly, the big cost in your NHibernate scenario is the call to BuildSessionFactory(). NHibernate is optimized to have cheap session construction, so it expects you to create this factory once and re-use it throughout the lifetime of your program. If you put trace points around this event, you may find your "expense".
If I had to take a wild guess here, the issue is not with nhibernate querying the database I think it is the initial cost you are paying to build the sessionFactory and/or session and that is why you are seeing the unusual latency.
Why dont you use Jetbrains dotTrace and see where is the actual performance hit, if its in running the query or something else. Just run a sampling query and you will be able to get the timings with the exact number of calls to each function.
P.S: I have no association with jetbrains just a happy customer recommending the product.
The problem ended up being that I didn't specify the datatype for the primary key column, which turned out to be varchar (non-unicode). Turns out you need to specify the datatype for non-unicode columns, as fluent assumes string maps to uni code.
This is how to set the custom type in fluent notation:
Map(x=>x.PersonId).CustomType("AnsiString");
Related
I am working on a MVC3 application with nhibernate and SQL server. Have written a normal method which is re-usable. Please find the below code and let me know a better way to handle it. I have observed to execute this piece of code it is taking a long time.
private void GetParentCompany(IEnumerable<Company> companiesList)
{
foreach (var company in companiesList)
{
long? dunsUltimateParent = company.DUNSUltimateParent;
Company ultimateParent = _companyService.GetCompanyByDUNS(Convert.ToInt64(dunsUltimateParent));
if (ultimateParent != null)
{
company.UltimateParentName = ultimateParent.CompanyName;
company.UltimateCompanyId = ultimateParent.CompanyId;
company.UltimateParentDuns = ultimateParent.DUNS;
}
}
}
Adding an index to your company.DUNS column might help. However consider to introduce a many-to-one relationship from company to (parent) company.
Place a UltimateParent property with type company in the company class. The fields UltimateParentName and UltimateParentDuns would then be redundant and you could simply get company.UltimateParent.Name for example. The mapping of UltimateParent can be done using 'References' in fluent-nhibernate.
References(x => x.UltimateParent);
I've only been using fluent nhibernate a few days and its been going fine until trying to deal with guid values and Oracle. I have read a good few posts on the subject but none that help me solve the problem I am seeing.
I am using Oracle 10g express edition.
I have a simple test table in oracle
CREATE TABLE test (Field RAW(16));
I have a simple class and interface for mapping to the table
public class Test : ITest
{
public virtual Guid Field { get; set; }
}
public interface ITest
{
Guid Field { get; set; }
}
Class map is simple
public class TestMap : ClassMap<Test>
{
public TestMap()
{
Id(x => x.Field);
}
}
I start trying to insert a simple easily recognised guid value
00112233445566778899AABBCCDDEEFF
Heres the code
var test = new Test {Field = new Guid("00112233445566778899AABBCCDDEEFF")};
// test.Field == 00112233445566778899AABBCCDDEEFF here.
session.Save(test);
// after save guid is changed, test.Field == 09a3f4eefebc4cdb8c239f5300edfd82
// this value is different for each run so I pressume nhibernate is assigning
// a value internally.
transaction.Commit();
IQuery query = session.CreateQuery("from Test");
// or
// IQuery query = session.CreateSQLQuery("select * from Test").AddEntity(typeof(Test));
var t in query.List<Test>().Single();
// t.Field == 8ef8a3b10e704e4dae5d9f5300e77098
// this value never changes between runs.
The value actually stored in the database differs each time also, for the run above it was
EEF4A309BCFEDB4C8C239F5300EDFD82
Truly confused....
Any help much appreciated.
EDIT: I always delete data from the table before each test run. Also using ADO directly works no problem.
EDIT: OK, my first problem was that even though I thought I was dropping the data from the table via SQL command line for oracle when I viewed the table via oracle UI it still had data and the first guid was as I should have expected 8ef8a3b10e704e4dae5d9f5300e77098.
Fnhibernate still appears to be altering the guid value on save. it alters it to the value it stores in the database but I'm still not sure why it is doing this or how\if I can control it.
If you intend on assigning the id yourself you will need to use a different id generator than the default which is Guid.comb. You should be using assigned instead. So your mapping would look something like this:
Id(x => x.Field).GeneratedBy.Assigned();
You can read more about id generators in the nhibernate documentation here:
http://www.nhforge.org/doc/nh/en/index.html#mapping-declaration-id-generator
I’m trying to optimize my app, and I notice that one query is triggered multiple times without any apparent reason.
Is a MVC 3 App, razor and I’m using Linq and EF.
I have ViewModel class with a couple of properties.
One of these properties is the model for to view.
This is my controller (I omit all the others properties initialization):
public ActionResult companyDetail(Guid id)
{
companyDetailsViewModel myModel = new companyDetailsViewModel();
myModel.companyDetail = companiesRepository.getCompany(id);
return View(myModel);
}
This is my getCompany method:
public company getCompany(Guid id)
{
return db.companies.Single(c => c.id == id);
}
The view is too long to paste here, but is a simple view.
This is a part for example:
<div id="companyName">
<h2>
#Model.companyDetail.companyName
</h2>
</div>
<div id="companyInfoWapper">
<div class="companyInfo">
<h5>
industry: #Model.companyDetail.industry<br />
revenue: #String.Format("{0:C}", Model.companyDetail.revenue)
</h5>
</div>
</div>
I’m using AnjLab SQL Profiler to view the transactions..
When I call the view, the query it’s
called 3 times.
The Generated SQL is
the exact same on all 3.
The transaction ID is different, and also
the duration varies a little bit.
The rest are pretty much the same.
Any Idea what can be making this query to run multiple times?
Another Question!
Anyone know why db.companies.Single(c => c.id == id) ask for top 2? Like this:
SELECT TOP (2)
[Extent1].[id] AS [id], ….
Thanks in Advance!
Edgar.
Update!
The third call was my fault, and I fix it. However, I find this:
The application is Multi-language, so I write a class that implements Controller.
I trace the problem to this class. The query is triggered the second time at the end of the class when I call the Base:
base.Execute(requestContext);
and of course, the action is called again.
Any Idea how to prevent this?
Another Update!
Linkgoron ask why I call Base.Execute(), the answer is because of the localizedController implementation.
But his question make me think, and there is another part of the code:
public abstract class LocalizedControllerBase : Controller
{
public String LanguageCode { get; private set; }
private String defaultLanguage = "es";
private String supportedLanguages = "en|es|pt";
protected override void Execute(RequestContext requestContext)
{
if (requestContext.RouteData.Values["languageCode"] != null)
{
LanguageCode = requestContext.RouteData.Values["languageCode"].ToString().ToLower();
if (!supportedLanguages.ToLower().Contains(LanguageCode))
{
LanguageCode = defaultLanguage;
}
}
else {
LanguageCode = defaultLanguage;
}
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture(LanguageCode);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
base.Execute(requestContext);
}
}
My controller are defined like this:
public class companiesController : LocalizedControllerBase
I put a break point in “Base.Execute” and another in the “return View(myModel)” in the controller.
When I call the view companyDetail, the first stop is in base.Execute, the second is in return view, but for some reason there is a third stop in Base.Execute and a fourth in Return View, and finally the view is render.
This is making me crazy!
Anyone know why db.companies.Single(c
=> c.id == id) ask for top 2? Like this:
SELECT TOP (2) [Extent1].[id] AS [id],
….
Single() throws an exception if there is not exactly one match - so the Linq to Entities provider translates that as a top 2 query which is enough data to make a decision - throw an exception if the query returns 2 results or none, return the only result otherwise.
This doesn't make sense. If the query is executed multiple times you must call GetCompany method multiple times. Once you call Single the query is executed and Company instance is materialized so using it multiple times in view will not cause new executions. Those another calls must be caused by different part of your code.
Btw. you can avoid them by using Find (in EF 4.1) or GetObjectByKey (in EFv1 and EFv4) instead of Single. Single always executes query in database whereas Find first checks if the entity with the same entity key was already loaded and returns the instance without executing db query:
This is code for DbContext API (EF 4.1):
public company getCompany(Guid id)
{
// Id must be primary key
return db.companies.Find(id);
}
Code for ObjectContext API is little bit complicated because you first have to build EntityKey which requires entity set name. Here I described full example which works with different key types and names.
I'm testing MongoDB 1.6.5 speed and C# in win64 machine. I use Yahoo.geoplanet as source to load states, county, towns but i'm not very performant. I have currently more 5 sec to load the US states from these source passing a List to a web page in localhost.
Use only id as index. Can someone suggest way to perform. Thanks
class BsonPlaces
{
[BsonId]
public String Id { get; set; }
public String Iso { get; set; }
public String Name { get; set; }
public String Language { get; set; }
public String Place_Type { get; set; }
public String Parent_Id { get; set; }
}
public List<BsonPlaces> Get_States(string UseCountry)
{
using (var helper = BsonHelper.Create())
{
var query = Query.EQ("Place_Type", "State");
if (!String.IsNullOrEmpty(UseCountry))
query = Query.And(query, Query.EQ("Iso", UseCountry));
var cursor = helper.GeoPlanet.PlacesRepository.Db.Places
.FindAs<BsonPlaces>(query);
if (!String.IsNullOrEmpty(UseCountry))
cursor.SetSortOrder(SortBy.Ascending("Name"));
return cursor.ToList();
}
}
I suppose problem not in mongodb, loading can be slow for two reasons:
You trying to load big count of 'BsonPlaces'(20000 for example or even more).
Some another code on page take much time.
For speed improvements you can:
1.Set limit to items that will be returned by query:
cursor.SetLimit(100);
2.Create indexes for 'Name', 'Iso', 'Place_Type':
helper.GeoPlanet.PlacesRepository.Db.Places.EnsureIndex("Name");
c# driver probably have big performance problem. A simple query for 100k times on shell takes 3 seconds, same query (written in c# linq of official c# driver 1.5) takes 30 seconds. Profiler tells each query from c# client takes less than 1 ms. So I assume c# driver is doing a lot of unnecessary stuffs that makes the query so slow.
Under mongodb 2.0.7, OS: windows 7, Ram: 16G.
I downloaded the GeoPlanet Data from Yahoo and found that the geoplanet_places_7.6.0.tsv file has 5,653,969 lines of data.
That means that in the absence of an index you are doing a "full table scan" of over 5 million entries to retrieve the 50 US states.
When querying for states within a country, the following index would probably be the most helpful:
...EnsureIndex("Iso", "Place_Type");
Not sure why you would want to search for all "States" without specifying a country, but you would need another index for that.
Sometimes when a sort is involved it can be advantageous for the index to match the sort order. For example, since you are sorting on "Name" the index could be:
...EnsureIndex("Iso", "Place_Type", "Name");
However, with only 50 states the sort will probably be very fast anyway.
I doubt any of your slow performance is attributable to the C# driver, but if after adding the indexes you still have performance problems let us know.
In trying to solve:
Linq .Contains with large set causes TDS error
I think I've stumbled across a solution, and I'd like to see if it's a kosher way of approaching the problem.
(short summary) I'd like to linq-join against a list of record id's that aren't (wholly or at least easily) generated in SQL. It's a big list and frequently blows past the 2100 item limit for the TDS RPC call. So what I'd have done in SQL is thrown them in a temp table, and then joined against that when I needed them.
So I did the same in Linq.
In my MyDB.dbml file I added:
<Table Name="#temptab" Member="TempTabs">
<Type Name="TempTab">
<Column Name="recno" Type="System.Int32" DbType="Int NOT NULL"
IsPrimaryKey="true" CanBeNull="false" />
</Type>
</Table>
Opening the designer and closing it added the necessary entries there, although for completeness, I will quote from the MyDB.desginer.cs file:
[Table(Name="#temptab")]
public partial class TempTab : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _recno;
#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnrecnoChanging(int value);
partial void OnrecnoChanged();
#endregion
public TempTab()
{
OnCreated();
}
[Column(Storage="_recno", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int recno
{
get
{
return this._recno;
}
set
{
if ((this._recno != value))
{
this.OnrecnoChanging(value);
this.SendPropertyChanging();
this._recno = value;
this.SendPropertyChanged("recno");
this.OnrecnoChanged();
}
}
}
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SendPropertyChanging()
{
if ((this.PropertyChanging != null))
{
this.PropertyChanging(this, emptyChangingEventArgs);
}
}
protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then it simply became a matter of juggling around some things in the code. Where I'd normally have had:
MyDBDataContext mydb = new MyDBDataContext();
I had to get it to share its connection with a normal SqlConnection so that I could use the connection to create the temporary table. After that it seems quite usable.
string connstring = "Data Source.... etc..";
SqlConnection conn = new SqlConnection(connstring);
conn.Open();
SqlCommand cmd = new SqlCommand("create table #temptab " +
"(recno int primary key not null)", conn);
cmd.ExecuteNonQuery();
MyDBDataContext mydb = new MyDBDataContext(conn);
// Now insert some records (1 shown for example)
TempTab tt = new TempTab();
tt.recno = 1;
mydb.TempTabs.InsertOnSubmit(tt);
mydb.SubmitChanges();
And using it:
// Through normal SqlCommands, etc...
cmd = new SqlCommand("select top 1 * from #temptab", conn);
Object o = cmd.ExecuteScalar();
// Or through Linq
var t = from tx in mydb.TempTabs
from v in mydb.v_BigTables
where tx.recno == v.recno
select tx;
Does anyone see a problem with this approach as a general-purpose solution for using temporary tables in joins in Linq?
It solved my problem wonderfully, as now I can do a straightforward join in Linq instead of having to use .Contains().
Postscript:
The one problem I do have is that mixing Linq and regular SqlCommands on the table (where one is reading/writing and so is the other) can be hazardous. Always using SqlCommands to insert on the table, and then Linq commands to read it works out fine. Apparently, Linq caches results -- there's probably a way around it, but it wasn't obviousl.
I don't see a problem with using temporary tables to solve your problem. As far as mixing SqlCommands and LINQ, you are absolutely correct about the hazard factor. It's so easy to execute your SQL statements using a DataContext, I wouldn't even worry about the SqlCommand:
private string _ConnectionString = "<your connection string>";
public void CreateTempTable()
{
using (MyDBDataContext dc = new MyDBDataContext(_ConnectionString))
{
dc.ExecuteCommand("create table #temptab (recno int primary key not null)");
}
}
public void DropTempTable()
{
using (MyDBDataContext dc = new MyDBDataContext(_ConnectionString))
{
dc.ExecuteCommand("DROP TABLE #TEMPTAB");
}
}
public void YourMethod()
{
CreateTempTable();
using (MyDBDataContext dc = new MyDBDataContext(_ConnectionString))
{
...
... do whatever you want (within reason)
...
}
DropTempTable();
}
We have a similar situation, and while this works, the issue becomes that you aren't really dealing with Queryables, so you cannot easily use this "with" LINQ. This isn't a solution that works with method chains.
Our final solution was just to throw what we want in a stored procedure, and write selects in that procedure against the temp tables when we want those values. It is a compromise, but both are workarounds. At least with the stored proc the designer will generate the calling code for you, and you have a black boxed implementation so if you need to do further tuning you can do so strictly within the procedure, without a recompile.
In a perfect world, there will be some future support for writing Linq2Sql statements that allow you to dicate the use of temp tables within your queries, avoid the nasty sql IN statement for complex scenarios like this one.
As a "general-purpose solution", what if you code is run in more than one threads/apps? I think big-list solution is always related to the problem domain. It's better to use a regular table for the problem you are working on.
I once created a "generic" list table in database. The table was created with three columns: int, uniqueidentifier and varchar, along with other columns to manage each list. I was thinking: "it ought to be enough to handle many cases". But soon I received a task that requires a join be performed with a list on three integers. After that, I never tried to create "generic" list table again.
Also, it's better to create a SP to insert multiple items into the list table in each database call. You can easily insert ~2000 items in less than 2 db round trips. Of cause, depending on what you are doing, performance may do not matter.
EDIT: forgot it is a temporary table and temporary table is per connection, so my previous argument on multi-threads was not proper. But still, it is not a general solution, for enforcing the fixed schema.
Would the solution offered by Neil actually work? If its a temporary table, and each of the methods is creating and disposing its own data context, I dont think the temporary table would still be there after the connection was dropped.
Even if it was there, I think this would be an area where you are assuming some functionality of how queries and connections end up being rendered, and thats ome of the big issues with linq to sql - you just dont know what might happen downt he track as the engineers come up with better ways of doing things.
I'd do it in a stored proc. You can always return the result set into a pre-defined table if you wish.