Kevin,
Here is the test. Generally, we simulate different number of concurrent users accessing the same database at the same time. Every user calls the method GetFeaturesInsideBoundingBox() 100 times with a random input extent. In our test, we uses a remote Sql2008 Server and a remote shape file (on the same machine of the Sql2008 Server) which has the same data. We get the average time for one Operation (layer.Open / layer.GetFeaturesInsideBoundingBox / layer.Close) and here is the result.
User Count
Remote Sql2008 (ms)
Remote ShapeFile(ms)
1
9.77
11.9
10
52.12
84.8
20
103
177.6
50
273
459
100
583
1431
So we can see, remote Sql2008 server is (1.5 to 2.5) times faster than a remote Shapefile under the same circumstance.
We also compared the average time between a Local ShapeFile and a Local Sql2008 Server. The result is interesting that the average time for an operation with a local shapeFile is almost the same no matter how many concurrent users are there, but for the local sql2008 server, it still grows linearly. I think that's because the operating system did pretty good caching for a local file, but didn't do much caching for a database. In the test we also found if we change the file path to a network path like “\\192.168.0.10\Share\Test.shp” instead of a local one like “c:\Share\Test.shp”, although the file is still the same , the performance will be much slower, in fact it will be about 1.5 to 2 times slower than the local Sql2008 server.
User Count
Local ShapeFile(ms)
Local Sql2008 (ms)
1
4.8
6.28
10
6.68
61.13
20
4.84
127
50
7.89
360
100
7.09
762
So we can say, the local shape file has the best performance because it is well cached. Other than that, Sql Server2008 will be around 2 times faster than a Shape File under the same circumstance.
Here is the key codes in the test. You can try if you are interested.
List<long> results = new List<long>();
// Start Sql Test
private void btnSql2008Test_Click(object sender, EventArgs e)
{
results.Clear();
int times = Convert.ToInt32(txtSql2008TestTimes.Text.Trim());
TestMultiThread(new ThreadStart(TestOneThreadOnSql2008), times);
}
// Start Shape File Test
private void btnShapeFileTest_Click(object sender, EventArgs e)
{
results.Clear();
int times = Convert.ToInt32(txtShapeTestTimes.Text.Trim());
TestMultiThread(new ThreadStart(TestOneThreadOnShapeFileFeatureLayer), times);
}
// Show Result
private void btnShowResult_Click(object sender, EventArgs e)
{
long sum = 0;
foreach (long item in results)
{
sum += item;
}
MessageBox.Show(((double)sum/(double)results.Count).ToString());
}
private void TestMultiThread(ThreadStart threadStart, int clients)
{
Thread[] threads = new Thread[clients];
for (int i = 0; i < threads.Length; i++)
{
threads[i] = new Thread(threadStart);
threads[i].Start();
}
}
private void TestOneThreadOnSql2008()
{
string connectString = @"Data Source=192.168.0.191\TGSQLSERVER; Initial Catalog=InternalDB; User ID=userId; Password=password;";
TempMsSql2008FeatureLayer sql2008Layer = new TempMsSql2008FeatureLayer(connectString, "states", "recid");
Take100Operations(sql2008Layer);
}
private void TestOneThreadOnShapeFileFeatureLayer()
{
ShapeFileFeatureLayer shapeFileFeatureLayer = new ShapeFileFeatureLayer(@"C:\Share\USStates.shp");
Take100Operations(shapeFileFeatureLayer);
}
private void Take100Operations(FeatureLayer sql2008Layer)
{
Random random = new Random(DateTime.Now.Millisecond);
// Do 100 operations
for (int i = 0; i < 10; i++)
{
RectangleShape extent = new RectangleShape(-126.4, 48.8, -67.0, 19.0);
extent.ScaleDown(50);
for (int j = 0; j < 10; j++)
{
extent.TranslateByOffset(random.Next(10), random.Next(10), GeographyUnit.Meter, DistanceUnit.Meter);
GetFeaturesWithinRectangle(sql2008Layer, extent);
}
}
}
private Collection<Feature> GetFeaturesWithinRectangle(FeatureLayer layer, RectangleShape extent)
{
Stopwatch sw = new Stopwatch();
sw.Start();
layer.Open();
Collection<Feature> features = layer.QueryTools.GetFeaturesInsideBoundingBox(extent, ReturningColumnsType.AllColumns);
layer.Close();
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
results.Add(sw.ElapsedMilliseconds);
return features;
}
Thanks,
Ben