Wie kann ich Performance eines webframeworks mit web.py erhöhen?

Django, Flask, Bottle, WSGI, CGI…
Antworten
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ich habe eine Webserver mit web.py erstellt.
In meiner Datenbank liegen Gebäudemodelle die in Kacheln eingeteilt sind!
Ergebnisse (Zeit gemessen mit web.profiler)
Wenn ich eine 400m Kachel (4137 rows) abfrage dauert die Ausführung und Übertragung zum Browser ca. 0.26 Sekunden.
Wenn ich eine 500m Kachel (6241) abfrage braucht die Ausführung und Übertragung zum Browser ca. 14 Sekunden.

Klar das die 500m Kachel länger braucht durch die höhere Anzahl von rows in der DB! Aber von 0,26 sekunden auf 14????
Ist das normal? Ich finde den Unterschied zu krass....

Mein Programm sieht folgendermaßen aus:

Code: Alles auswählen

import cx_Oracle
import json
import web

urls = (
"/", "index",
"/grid", "grid",
)
app = web.application(urls, globals(),web.profiler )
web.config.debug = True


connection = cx_Oracle.Connection("TEST_3D/limo1013@10.40.33.160:1521/sdetest")
typeObj = connection.gettype("MDSYS.SDO_GEOMETRY")

class index:
    def GET(self):
		return "hallo moritz " 

class grid:

	def GET(self):
		web.header('Access-Control-Allow-Origin',      '*')
		web.header('Access-Control-Allow-Credentials', 'true')		
		web.header('Content-Type', 'application/json')
		
		cursor = connection.cursor()
		cursor.arraysize = 6300 # default = 50
		cursor.execute("""SELECT a.id , c.geometry, d.Classname FROM   building a, THEMATIC_SURFACE b, SURFACE_GEOMETRY c, OBJECTCLASS d  WHERE  a.grid_id_400 = 4158 AND a.id = b.BUILDING_ID AND b.LOD2_MULTI_SURFACE_ID = c.ROOT_ID AND c.GEOMETRY IS NOT NULL AND b.OBJECTCLASS_ID = d.ID""")

		def geometry_to_points(obj):
			return zip(*[iter(obj.SDO_ORDINATES.aslist())]*3)

		result = []
		for id, geometry, classname in cursor:
			result.append({
			"building_nr": id, "geometry": {
				"type": "polygon",
				"coordinates": [geometry_to_points(geometry)],
				}, "polygon_typ": classname,
			})
		return json.dumps(result)

# Aufruf der App		
if __name__ == "__main__": 
		app.run(web.profiler)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@moehre: hast Du schon geschaut, was Oracle-EXPLAIN dazu meint?
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ja da sieht aber alles normal aus

Oracle sql developer

400m:
Elapsed: 00:00:00.003
Plan hash value: 4070057891

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 149 | 19072 | 3847 (1)| 00:00:47 |
|* 1 | HASH JOIN | | 149 | 19072 | 3847 (1)| 00:00:47 |
| 2 | TABLE ACCESS FULL | OBJECTCLASS | 106 | 2226 | 3 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 149 | 15943 | 3844 (1)| 00:00:47 |
| 4 | NESTED LOOPS | | 2679 | 15943 | 3844 (1)| 00:00:47 |
| 5 | NESTED LOOPS | | 893 | 22325 | 270 (0)| 00:00:04 |
| 6 | TABLE ACCESS BY INDEX ROWID| BUILDING | 87 | 870 | 14 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | INDEX1 | 87 | | 1 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID| THEMATIC_SURFACE | 10 | 150 | 3 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | THEM_SURFACE_BUILDING_FKX | 10 | | 2 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | SURFACE_GEOM_ROOT_FKX | 3 | | 2 (0)| 00:00:01 |
|* 11 | TABLE ACCESS BY INDEX ROWID | SURFACE_GEOMETRY | 1 | 82 | 4 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

500m:
Zeigt nur den Ausführungsplan an.
Elapsed: 00:00:00.003
Plan hash value: 3532878181

-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 202 | 25856 | 5208 (1)| 00:01:03 |
|* 1 | HASH JOIN | | 202 | 25856 | 5208 (1)| 00:01:03 |
| 2 | TABLE ACCESS FULL | OBJECTCLASS | 106 | 2226 | 3 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 202 | 21614 | 5205 (1)| 00:01:03 |
| 4 | NESTED LOOPS | | 3630 | 21614 | 5205 (1)| 00:01:03 |
| 5 | NESTED LOOPS | | 1210 | 30250 | 363 (0)| 00:00:05 |
| 6 | TABLE ACCESS BY INDEX ROWID| BUILDING | 118 | 1180 | 16 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | INDEX4 | 118 | | 1 (0)| 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID| THEMATIC_SURFACE | 10 | 150 | 3 (0)| 00:00:01 |
|* 9 | INDEX RANGE SCAN | THEM_SURFACE_BUILDING_FKX | 10 | | 2 (0)| 00:00:01 |
|* 10 | INDEX RANGE SCAN | SURFACE_GEOM_ROOT_FKX | 3 | | 2 (0)| 00:00:01 |
|* 11 | TABLE ACCESS BY INDEX ROWID | SURFACE_GEOMETRY | 1 | 82 | 4 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------


Ergebnis im Browser:

400m:
took 0.258000135422 seconds
4774 function calls (4765 primitive calls) in 0.859 seconds

Ordered by: internal time, call count
List reduced from 45 to 40 due to restriction <40>

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.348 0.348 0.737 0.737 template.py:22(GET)
1 0.223 0.223 0.223 0.223 encoder.py:212(iterencode)
4137 0.153 0.000 0.153 0.000 template.py:31(geometry_to_points)
360 0.064 0.000 0.093 0.000 application.py:663(check)
182 0.029 0.000 0.029 0.000 genericpath.py:23(exists)
1 0.026 0.026 0.763 0.763 application.py:389(handle_class)
1 0.009 0.009 0.232 0.232 encoder.py:186(encode)
1 0.004 0.004 0.236 0.236 __init__.py:193(dumps)
1 0.001 0.001 0.094 0.094 application.py:659(__call__)
1 0.000 0.000 0.000 0.000 application.py:338(load)
13 0.000 0.000 0.000 0.000 utf_8.py:15(decode)
2 0.000 0.000 0.000 0.000 utils.py:521(re_subm)
1 0.000 0.000 0.859 0.859 application.py:269(wsgi)
1 0.000 0.000 0.000 0.000 httpserver.py:308(log)
1 0.000 0.000 0.000 0.000 basehttpserver.py:475(log_date_time_string)
5/1 0.000 0.000 0.858 0.858 application.py:233(process)
1 0.000 0.000 0.858 0.858 application.py:579(processor)
3 0.000 0.000 0.000 0.000 utils.py:536(group)
8 0.000 0.000 0.000 0.000 utils.py:356(safestr)
1 0.000 0.000 0.000 0.000 utils.py:1210(clear_all)
1 0.000 0.000 0.000 0.000 application.py:75(reload_mapping)
2 0.000 0.000 0.000 0.000 utils.py:487(__call__)
1 0.000 0.000 0.000 0.000 application.py:426(_match)
3/1 0.000 0.000 0.858 0.858 application.py:564(processor)
1 0.000 0.000 0.763 0.763 application.py:388(_delegate)
1 0.000 0.000 0.000 0.000 __init__.py:2035(start_response)
1 0.000 0.000 0.000 0.000 application.py:114(init_mapping)
13 0.000 0.000 0.000 0.000 utils.py:1223(__setitem__)
1 0.000 0.000 0.763 0.763 application.py:228(handle)
7 0.000 0.000 0.000 0.000 utils.py:545(take)
3 0.000 0.000 0.000 0.000 webapi.py:260(header)
1 0.000 0.000 0.000 0.000 application.py:97(_unload)
1 0.000 0.000 0.000 0.000 application.py:109(_cleanup)
4/1 0.000 0.000 0.858 0.858 application.py:237(<lambda>)
1 0.000 0.000 0.000 0.000 httpserver.py:301(xstart_response)
1 0.000 0.000 0.858 0.858 application.py:232(handle_with_processors)
2 0.000 0.000 0.000 0.000 utils.py:1234(clear)
1 0.000 0.000 0.000 0.000 os.py:446(get)
1 0.000 0.000 0.000 0.000 application.py:398(is_class)
1 0.000 0.000 0.000 0.000 utils.py:1246(iteritems)

500m:
took 14.1860001087 seconds
6880 function calls (6871 primitive calls) in 47.042 seconds

Ordered by: internal time, call count
List reduced from 47 to 40 due to restriction <40>

ncalls tottime percall cumtime percall filename:lineno(function)
6241 45.735 0.007 45.735 0.007 template.py:31(geometry_to_points)
1 0.735 0.735 46.894 46.894 template.py:22(GET)
1 0.403 0.403 0.403 0.403 encoder.py:212(iterencode)
360 0.074 0.000 0.107 0.000 application.py:663(check)
1 0.038 0.038 46.932 46.932 application.py:389(handle_class)
182 0.033 0.000 0.033 0.000 genericpath.py:23(exists)
1 0.013 0.013 0.416 0.416 encoder.py:186(encode)
1 0.008 0.008 0.424 0.424 __init__.py:193(dumps)
1 0.001 0.001 0.109 0.109 application.py:659(__call__)
1 0.000 0.000 0.000 0.000 application.py:338(load)
13 0.000 0.000 0.000 0.000 utf_8.py:15(decode)
1 0.000 0.000 47.042 47.042 application.py:269(wsgi)
1 0.000 0.000 0.000 0.000 httpserver.py:308(log)
2 0.000 0.000 0.000 0.000 utils.py:521(re_subm)
1 0.000 0.000 0.000 0.000 basehttpserver.py:475(log_date_time_string)
1 0.000 0.000 0.000 0.000 utils.py:1210(clear_all)
5/1 0.000 0.000 47.041 47.041 application.py:233(process)
2 0.000 0.000 0.000 0.000 utils.py:487(__call__)
1 0.000 0.000 47.041 47.041 application.py:579(processor)
8 0.000 0.000 0.000 0.000 utils.py:356(safestr)
1 0.000 0.000 0.000 0.000 application.py:426(_match)
3 0.000 0.000 0.000 0.000 utils.py:536(group)
1 0.000 0.000 0.000 0.000 __init__.py:2035(start_response)
1 0.000 0.000 46.932 46.932 application.py:388(_delegate)
3/1 0.000 0.000 47.041 47.041 application.py:564(processor)
1 0.000 0.000 0.000 0.000 application.py:75(reload_mapping)
13 0.000 0.000 0.000 0.000 utils.py:1223(__setitem__)
1 0.000 0.000 0.000 0.000 application.py:114(init_mapping)
7 0.000 0.000 0.000 0.000 utils.py:545(take)
3 0.000 0.000 0.000 0.000 webapi.py:260(header)
1 0.000 0.000 0.000 0.000 application.py:97(_unload)
1 0.000 0.000 46.932 46.932 application.py:228(handle)
1 0.000 0.000 0.000 0.000 utils.py:1201(__init__)
1 0.000 0.000 0.000 0.000 httpserver.py:301(xstart_response)
4/1 0.000 0.000 47.041 47.041 application.py:237(<lambda>)
1 0.000 0.000 0.000 0.000 application.py:109(_cleanup)
1 0.000 0.000 47.041 47.041 application.py:232(handle_with_processors)
1 0.000 0.000 0.000 0.000 os.py:446(get)
2 0.000 0.000 0.000 0.000 utils.py:1234(clear)
1 0.000 0.000 0.000 0.000 utils.py:1246(iteritems)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

das ist doch eindeutig: geometry_to_points braucht wesentlich länger. Schau mal nach, wieviele Punkte Du denn bei 500m-Kacheln abfragst.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ok.
Ich frage 6341 rows ab. Das sind ca. 43.6871 Punkte.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Lass ich die Geometry komplett raus sind es nur noch 0,2 sekunden!!! ok also liegt es überwiegend an der Funktion...
Das heißt ohne das ich die in Punkte umwandle, alleine die Funktion: "coordinates": geometry.SDO_ORDINATES.aslist() reicht aus um die Zeit auf 14 sekunden hochzutreiben.

Mir bleibt nichts anderes übrig ich brauch die Koordinaten. Muss nicht als Punkt sein aber wenigstens als Liste. Das liegt jedoch beides bei 14 Sekunden!
Gibt es da irgenwie eine Möglichkeit das zu beschleunigen???
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@moehre: wieviele Punkte sind denn das jetzt? Das Problem liegt bei Oracle. Vielleicht kann man es überreden, die Punkte in einer anderen Form zu liefern.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Wie gesagt Anzahl der Polygone 6341. Und diese beinhalten immer eine unterschiedliche Anzahl an Punkten. In der Regel so 6-7 Punkte pro Polygon. Also insgesamt ca. 43.6871Punkte.

Innerhalb der Datenbank in Oracle liegen diese Objekte als SDO_GEOMETRY vor. Du meinst wenn ich diese konvertiere in ein anderes Format wäre es schneller?
Das Problem ist in meinem Unternehmen gibt es nur Oracle Locator. Das heißt ich kann die 3D-Geometrien nicht konvertieren. Funktionen auf 3D-Geometrien sind in Locator nicht gestattet.

Das einzige was ich noch gesehen habe . Es gibt eine Funktion in Oracle (selbsterstellt) mit der kann ich die SDO_GEOMETRY in GeoJSON umwandeln. Würde es Sinn machen diese Funktion im Webserver aufzurufen und zu schauen ob es schneller geht?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@moehre: wenn sich die Punktanzahl linear mit der Anzahl der Polygone vergrößert, wäre die Anfrage in 0.4s erledigt. Also muß es etwas anderes sein, also entweder einzelne Polygone, die sehr viel mehr Punkte haben, oder aus anderen Gründen dort die Abfrage deutlich länger braucht. An Deiner Stelle würde ich mal von allen Polygonen die Punkte abfragen und messen, wie lange das jeweils braucht.
moehre
User
Beiträge: 39
Registriert: Donnerstag 21. April 2016, 13:50

Ergebnisse

400m Kachel:
23.707 Punkte (0.25s)

500m Kachel:
35.727 Punkte (14s)

Das heißt ich habe ein weniger als das doppelte!
Antworten