ThinkGeo.com    |     Documentation    |     Premium Support

PostgreFeatureLayer exception again

Hi,


It seems I am not lucky with the PostgreFeatureLayer, I got another exception:NpgsqlException was unhandled,


ERROR:57014: Cancelling statement due to user request.


I got this exception at this line of code first: Map1.CurrentExtent=postgrePlineLayer.GetBoundingBox()


When there is not much data returned from the database, no exception, I tried to get 17859 records from the database, then got this exception.


Is this a bug?


Thanks


Rose


 


 



Rose, 
  
 Checked in Google and seems many Postgre users has this problem. We will keep searching and let you know if we find anything. 
  
 Thanks, 
  
 Ben

Ben:



I tried using following format of connection string, the porblem solved.
Server=127.0.0.1;Port=5432;Database=myDataBase;User Id=myUsername;Password=myPassword;Timeout=20;
 
The CommandTimeout parameter is measured in seconds and controls for how long to wait for a command to finish before throwing an error.
 
 

Rose 

Rose, 
  
 Thanks very much for sharing the solution, that will be very helpful! 
  
 Ben.

Hi,


I have 10,326,986 records in my database, and have indexed the key columns. I wanted to select a subset of the data, got the same exception again although I have set the Timeout=300 in the connection string.


My database will keep growing. How can I retrieve a subset data?


Thanks


Rose



Rose, 
 We cannot recreate your problem based on a database size of 2000000 records, much smaller compare to your 10,326,986 records. 
  
 We will try to create a comparable database and recreate your problem as soon as possible, I guess this problem may exists in a third party Postgre DLL Npgsql.dll which is an open source project. 
  
 Thanks for your sharing. 
 Yale 


Yale:


Is there a limit on the PostgreFeatureLayer somewhere? When I had less data, I had no problem at all. But when I have lots of data, even I wanted to get a very small set data, I got the exception. It is really frustrated!


Rose



Rose,


We finally recreated the problem. I think what you need to do just reset the timeout as following:
 

postgreLayer.CommandTimout = 5000; //( or more)

 
The default value is 20, means it will fail and throw the exception “ERROR:57014: Canceling statement due to user request.” When the execution will exceed more than 20 seconds.
 
Any more questions just let me know.
 
Thanks
Yale.

Posted By Yale on 06-04-2009 01:22 AM 

Rose,


We finally recreated the problem. I think what you need to do just reset the timeout as following:
 



postgreLayer.CommandTimout = 5000; //( or more)


 
The default value is 20, means it will fail and throw the exception “ERROR:57014: Canceling statement due to user request.” When the execution will exceed more than 20 seconds.
 
Any more questions just let me know.
 
Thanks
Yale.




Yale:

 


I can’t find the “CommandTimout” property from the PostgreFeatureLayer, by the way, I can’t find the PostgreFeatureLayer in the API Document either.


I tried this connection string:


"Server=192.168.0.2;Port=5432; User ID=MyID; Password=MyPassword; Database=myDatabase;CommandTimeout=6000;Timeout=1024"


I still got the exception very quickly if I call postgreFeatureLayer.QueryTools.getCount() after I created the postgreFeatureLayer, did not wait for that long time.


One thing I should mention, I have another program is reading data from a TCP port and write data into the database. So the databse is growing every second.


Any help is greatly appriciated!


Thanks


Rose



Rose, 
  
 Please just have a try. Donot set the CommandTimeout in the connection string. Set it in the postgreSqlFeatureLayer you used.  We did see the difference between them. 
  
 See the code below: 
  
 PostgreSqlFeatureLayer postgreFeatureLayer = new PostgreSqlFeatureLayer(); 
 postgreFeatureLayer.CommandTimeout = 5000; 
  
 Now we are trying to generating a much more bigger data postgre server as your data set(around 10 million) to recreate your problem. 
  
 Any update will let you know. 
 Thanks. 
 Yale 


Yale:


Thank you very much for your time! It works better by setting the CommandTimeout in the posgreSQLFeatureLayer instead of in the Connection string, but still get the exception sometimes, maybe the server machine is busy then.


It only took about 4 minutes to retrieve a subset data of 2,650,205 rows,  but took more than 1 hour to get the data displayed on the map. In my program, I set a busy curor before I create the postgreSQLFeatureLayer, this will tell the user the program is working, please wait. After Map1.Refresh(), I reset the cursor to default, so after about 4 minutes, my cursor is set to default.


But it took more than 1 hour after the Map1.Refresh() is called  to get the map displayed, how can I tell the user the program is busy processing the data? BTW, I am using single threaded mode, and my program is single threaded.


Thanks


 



Yale:


I tried the new intrim build 3.0.314, retrieved the same amount of data from the same database, it took more than double the time than the previous build.


In my program, I created a customed point style called RotatePointStyle by extending the Style class, as discussed in following post:


gis.thinkgeo.com/Support/Dis...fault.aspx


so the style for each feature is rotated based on the information in column "TrueHeading".


I checked the PostgreSQL server,the program first launched a query to retrieve the subset data, then after more than an hour, the program launched another query to retrieve "TrueHeading" and the geometry columns only.


Why it needs to do two queries? Is this a bug? If not, definitely it is a performance issue.


Rose



Rose, 
  
 We will double check the time doubled as you said. 
  
 I think the two reason for the second time to query the Postgre Server is that when we draw, we will fetch data from the later with the column required. 
  
 I am wondering whether you put the subset of the first query into another PostgreSqlLayer, if so, try to put it into a InmemoryFeatureLayer as your another post talked about. 
  
 Thanks for your reply and questions.  
  
 Yale. 


Posted By Yale on 06-08-2009 02:06 AM 

Rose, 



We will double check the time doubled as you said. 



I think the two reason for the second time to query the Postgre Server is that when we draw, we will fetch data from the later with the column required. 



I am wondering whether you put the subset of the first query into another PostgreSqlLayer, if so, try to put it into a InmemoryFeatureLayer as your another post talked about. 



Thanks for your reply and questions. 



Yale. 




Yale:

 


I checked the program again, and narrowed down the problem. I think there is a refresh issue in this intrim release: 3.0.314 which does not have in release 307.


Following is my code snippet which creates the PostgreSQLFeatureLayer, same as release 307, after about 3 minutes, the code after Map1.Refresh() was executed, and it printed the Time=165, and my window cursor was set to default. After half an hour instead of one hour, I tried to pan and zoom in the map, I noticed the program sent another query to the database server to query the “TrueHeading” and the geometry columns for display. If I don’t do anything on the map for example pan/zoom in/out, the data will never get displayed.  After I added this line of code(Map1.Overlays(“VesselPointsOverlay”).Lock.isDirty=true)  before Map1.Refresh(), the problem got fixed. p>


 



Dim rectangleShape1 As RectangleShape = Map1.CurrentExtent
Dim projWGS84ToMercator As New Proj4Projection(" updated="" and="" ais_geom="" where="" aismessages1="" from="" select="" as="" vesselsview="" view="" replace="" or="" create="">= Date ‘2009-06-04’ AND updated< Date ‘2009-06-09’" Dim time1 As Date = Now Dim VesselPointsLayerview As New PostgreSqlFeatureLayer(connectString, “aismessages1”, “aismessages1_id”) VesselPointsLayerview.CommandTimeout = 6000 VesselPointsLayerview.Srid = 4326 VesselPointsLayerview.Open() VesselPointsLayerview.ExecuteNonQuery(sPointDataQryString) VesselPointsLayerview.Close() Dim VesselPointsLayer As New PostgreSqlFeatureLayer(connectString, “vesselsview”, “aismessages1_id”) VesselPointsLayer.Srid = 4326 VesselPointsLayer.CommandTimeout = 6000 VesselPointsLayer.FeatureSource.Projection = projWGS84ToMercator Try VesselPointsLayer.Open() Console.WriteLine(“VesselPointsLayer=” & VesselPointsLayer.QueryTools.GetCount) If CType(VesselPointsLayer.FeatureSource, PostgreSqlFeatureSource).GetCount() = 0 Then MsgBox(“No data selected”) Me.Cursor = Cursors.Default Exit Sub End If VesselPointsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Clear() VesselPointsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(New RotatePointStyle(New PointStyle(New GeoImage(appPath & “activated0000.png”)), “trueheading”)) VesselPointsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20 Catch ex0 As Npgsql.NpgsqlException MsgBox(“Too much data, please limit your selection to a smaller set and try again.”) Finally VesselPointsLayer.Close() End Try If Map1.FindFeatureLayer(“VesselPointsLayer”) Is Nothing = True Then Dim staticOverlay As New LayerOverlay() staticOverlay.Layers.Add(“VesselPointsLayer”, VesselPointsLayer) Map1.Overlays.Add(“VesselPointsOverlay”, staticOverlay) Else Try Map1.Overlays(“VesselPointsOverlay”).Lock.EnterWriteLock() CType(Map1.Overlays(“VesselPointsOverlay”), LayerOverlay).Layers.RemoveAt(0) CType(Map1.Overlays(“VesselPointsOverlay”), LayerOverlay).Layers.Add(“VesselPointsLayer”, VesselPointsLayer) Catch ex1 As Exception swLog.WriteLine(“DownloadPointData Exception::” + ex1.Message() + " Time is: " + DateTime.Now) swLog.Flush() Finally Map1.Overlays(“VesselPointsOverlay”).Lock.ExitWriteLock() End Try End If Map1.Refresh() Console.WriteLine(“Time=” & DateDiff(DateInterval.Second, time1, Now)) Catch ex As Exception swLog.WriteLine(“DownloadPointData Exception::” + ex.Message() + " Time is: " + DateTime.Now) swLog.Flush() Finally Me.Cursor = Cursors.Default End Try 
Rose



Rose, 


We double-checked the time between the interim releases (3.0.314) with 3.0.307 RC, we found the time spent to retrieve 50000 records from 190000 records database is almost the same, the 3.0.314 is about 20% faster as we expected.
 
So I guess there might be some other codes problem caused the bad performance.
 
We reviewed the code you pasted, it seems you have added the Lock system as required in the else statement, but you did not do it in the If statement.
 
Besides, I don’t think you need to add line of code( Map1.Overlays(“VesselPointsOverlay”).Lock.IsDirty = true), because we DONOT suggest you manually set the Overlay.Lock.IsDirty= true. Just try use the Try .. Finally stuff to add the Lock as you did in other way.

if (winformsMap1.FindFeatureLayer("TestLayer") == null)
            {
                LayerOverlay staticOverlay = new LayerOverlay();
                staticOverlay.Lock.EnterWriteLock();
                try
                {
                    staticOverlay.Layers.Add("TestLayer", postgreLayer2);
                    winformsMap1.Overlays.Add("TestOverlay", staticOverlay);
                }
                finally
                {
                    staticOverlay.Lock.ExitWriteLock();
                }
                // DONOT suggest do this 
    // staticOverlay.Lock.IsDirty = true;
            }
            else
            {
                try
                {
                    winformsMap1.Overlays["TestOverlay"].Lock.EnterWriteLock();
                    ((LayerOverlay)winformsMap1.Overlays["TestOverlay"]).Layers.RemoveAt(0);
                    ((LayerOverlay)winformsMap1.Overlays["TestOverlay"]).Layers.Add(postgreLayer2);
                }
                finally
                {
                    winformsMap1.Overlays["TestOverlay"].Lock.ExitWriteLock();
                }
            }

Any more problems just let me know.


Thanks.
Yale

Yale:


Thanks for your time. I thought there is no need to use the Lock system when first create the Overlay, it is only needed when edit/update the overlay. The same code worked in 3.0.307. Also in the Sample programs, the Lock system isn't used when createing a new overlay. Anyway, I used the Lock system in my If statement, I can see from the database server side the program sent the "Select Count(ID) from datatable" query then immediately by this query:


Select  "trueheading", AsBinay("ais_geom") as "ais_geom", "id" from datatable where GeomFromWKB($1:bytea,4326) && "ais_geom"


I think this is for displaying the data on the map. This step is very slow, I tried to retrieve 507,285 records from 3.397,904 records database, it took about 4 hours to get the data displayed.


After the data is displayed, I enlarged my map window, the program sent above two queries again to the database server, which means I will have to wait for another 4 hours to see the data.


Also I tried to shut down my program, but check the database server side, it is still running the the query I mentioned above, although my program has closed the database connection when it shuts down.  How to make sure the time-consuming queries are cancelled when the program shuts down?


Is the data downloaded to the local PC? If so, why it retrieves the data from the database server again when the map window size is changed? If not, is this efficient?


Thanks


Rose


 



 Rose,


I really hope my response can give you help and make your project move forward.
 


        
  1. We did not make any change for the Lock system between 3.0.307 RC and 3.0.314 interim version. So I guess the possible reason you talked about is that in your sample code, you change some places setting the CurrentExtent which will probably affect the result.


      Any all, I think this is not a big of deal.
 
 

        
  1. About the 4 hours to get the data displayed.


 
We tested it with about 2 million records Postgre server, it will only take a couple of minutes to draw all of them. I think the main difference is that we just use the normal Style( LineStyle and my CustomLineStytle which is very similar to RoatePointStyle) and you mentioned that you use the RotatePointStyle.  Can you try to remove this style to see the difference of performance?
I think this point is the most important part. We should focus on this and find out the reason to make the performance so unexpectedly badly?
 
If possible, can you send us the codes and a connection string which can access you postgre server for us, we will try to dig out the problem.
 

        
  1. About shut down the Server sql statement when the problem is shut down.


We did not find a good solution for this. Currently, I suggest you shut down it in the server side.
 

        
  1. When the map window size is changed? We probably need to fetch data again because every time we draw, we only will fetch the data needed for this Map window extent, if the extent enlarged, we will fetch the newly data.


Any more questions just let me know. Sorry for the convenience to you.
 
Thanks.
 
Yale

Yale:


Thanks for your time again!


1. About the 4 hours to get the data displayed


     I tried to remove the style and used the default style, it does get better,it took about 2 hours instead of 4 hours to get the same dataset displayed. How many minutes did it take you to draw 2 million records?


     But my boss still doesn't think 2 hours is acceptable.


     For some reasons, I can not let you access our database. I tell you more about my database. It stores the geometry in WGS84 projection, but we need to display the data in World Mercator projection, so need to do a convertion from SRID 4326 to SRID 3395, this may cost some time. Also there is another program is adding data to the database every second. Hope you can help me to find a way to improve the performance.


2. When window size changed, how to stop the data being fetched again?


When I create the postgreSQLFeature layer, I passed in a query string, within the query string, I specifed the area of interest and some other features, we really want to get the data within that area no matter the window/map size, once we get the data, we need to do some statistical analysis. If the data is changed based on the map size, our analysis won't be right.


Thanks


Rose



Rose,


You are welcome.


 


        
  1. About the 4 hours to get the data displayed.


We already tried everything we can to simulate your case. In our test App, we will project the data from database from SRID 4326 to SRID 3395.  Beside, we create another always-running program to insert data into the database at the speed of 100Records/seconds.
 
Following our test results based on a new created Posgre data (One thing I want to point out is that our PostgreServer and our App is in the same local internet):
 
PostgreServer table result: 1.4 million records with 13 record columns.
Fetch 535000 records with all columns as required are 57 seconds.
Fetch 535000 records with no columns as required are 38 seconds.
Fetch 167000 records with all columns as required are 15 seconds.
Fetch 167000 records with no columns as required are 13 seconds.
 

        
  1. When window size changed, how to stop the data from being fetched again?


 
I think to fetch data again is very common and our default implementation, if you want to stop it, you can create your own PostgreFeatureSource and PostgreFeatureLayer.
 
Below is our implementation which you can take a reference, hope this can give you some help.


//Create your own cached data featureSource.
public class CustomPostgreFeatureSource : PostgreSqlFeatureSource
    {
        private bool isDataFetched;
        private Collection<Feature> cachedFeatures;

        public bool IsDataFetched
        {
            get { return isDataFetched; }
        }

        public CustomPostgreFeatureSource()
            : this(string.Empty, string.Empty, string.Empty)
        { }

        public CustomPostgreFeatureSource(string connectionString, string tableName, string featureIdColumn)
            : this(connectionString, tableName, featureIdColumn, -999)
        {
        }

        public CustomPostgreFeatureSource(string connectionString, string tableName, string featureIdColumn, int srid)
            : base(connectionString,tableName,featureIdColumn,srid)
        {
            isDataFetched = false; 
        }

        public CustomPostgreFeatureSource(NpgsqlConnection connection, string tableName, string featureIdColumn)
            : this(connection, tableName, featureIdColumn, -999)
        {
        }

        public CustomPostgreFeatureSource(NpgsqlConnection connection, string tableName, string featureIdColumn, int srid)
            : base(connection,tableName,featureIdColumn,srid)
        {
            isDataFetched = false;
        }

        protected override Collection<Feature> GetFeaturesInsideBoundingBoxCore(RectangleShape boundingBox, IEnumerable<string> returningColumnNames)
        {
            if (!isDataFetched)
            {
                cachedFeatures = base.GetFeaturesInsideBoundingBoxCore(boundingBox, returningColumnNames);
                isDataFetched = true;
            }
            return cachedFeatures;
        }
    }

//Create your own featureLayer.
  public class CustomPostgreFeatureLayer : PostgreSqlFeatureLayer
    {
        public CustomPostgreFeatureLayer()
            : this(string.Empty, string.Empty, string.Empty, -999)
        { }

        public CustomPostgreFeatureLayer(string connectionString, string tableName, string featureIdColumn)
            : this(connectionString, tableName, featureIdColumn, -999)
        {
        }

        public CustomPostgreFeatureLayer(string connectionString, string tableName, string featureIdColumn, int srid)
            : base()
        {
            FeatureSource = new CustomPostgreFeatureSource(connectionString, tableName, featureIdColumn, srid);
            SetupTools();
        }

        public CustomPostgreFeatureLayer(NpgsqlConnection connection, string tableName, string featureIdeColumn)
            : this(connection, tableName, featureIdeColumn, -999)
        {
        }

        public CustomPostgreFeatureLayer(NpgsqlConnection connection, string tableName, string featureIdeColumn, int srid)
            : base()
        {
            FeatureSource = new CustomPostgreFeatureSource(connection, tableName, featureIdeColumn, srid);
            SetupTools();
        }
    }

//Useage.
CustomPostgreFeatureLayer postgreLayer = new CustomPostgreFeatureLayer(connectString, "rail", "oid");//fllkaa40
            
postgreLayer.CommandTimeout = 6000;
postgreLayer.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.Railway1;
           
postgreLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

 


Any more questions just let me know.
 
Thanks.
 
Yale