before the people cache was never used, because the 'args' parameter in
the 'self._people_cache.get(args)' call was a list/tuple object; but the
people cache dictionary has only strings as keys
-> so there were always database queries for the persons which slowed
down the sync process
also renamed 'args' to 'name', because basically a person gets searched
only by its name (see queries.py)
Note: This has a previously applied optimization of using a local cache.
Before:
```
458570 66.934 0.000 66.934 0.000 {method 'execute' of 'sqlite3.Cursor' objects}
246771 58.075 0.000 58.075 0.000 {method 'fetchone' of 'sqlite3.Cursor' objects}
```
After:
```
368883 66.220 0.000 66.220 0.000 {method 'execute' of 'sqlite3.Cursor' objects}
157084 58.160 0.000 58.160 0.000 {method 'fetchone' of 'sqlite3.Cursor' objects}
```
Once again, the number of calls to execute and fetchone are reduced but
the total time spent executing each is relatively stable.
Profiling has shown that there are many calls to sqlite3.execute and
fetchone which takes a signicant amount of time. A simple way of
reducing these is to swap the 2-stage init of table row data into a
unified add.
Applying this to add_set and add_country yielded these results:
Before changes
```
281784 7.054 0.000 7.054 0.000 {method 'execute' of 'sqlite3.Cursor' objects}
127443 1.114 0.000 1.114 0.000 {method 'fetchone' of 'sqlite3.Cursor' objects}
```
After changes
```
281714 7.492 0.000 7.492 0.000 {method 'execute' of 'sqlite3.Cursor' objects}
127373 1.217 0.000 1.217 0.000 {method 'fetchone' of 'sqlite3.Cursor' objects}
```
Note: The total time of fetchone has actually increased. I am hoping
this was an abnormality on my machine and the actual reduction in the
number of calls will permantly reduce this total time.
* Added profiling info
* Resort to the expensive database lookup only if the person exists in the
database.
* Prevent any access to the people database unless a person must be added.
* Bulk operations where possible.
* Prepare for a new install and the table not existing.
implementation dependant although with CPython elements are
unintentionally skipped during iteration.
Basic CPython example:
>>> A = [1,2,3,4,5,6]
>>> for a in A:
... A.remove(a)
>>> A
[2, 4, 6]