Details
-
Type:
Improvement
-
Status: Done/Fixed
-
Priority:
Minor
-
Resolution: Fixed/Completed
-
Affects Version/s: 4.4.6
-
Fix Version/s: 4.7.25
-
Component/s: CiviCRM API, NYSS
-
Labels:
-
Versioning Impact:Major (incompatible API change)
-
Documentation Required?:None
-
Funding Source:Core Team Contract
-
Payment Status:Paid
Description
We have a custom contact search form task. The search parameters could easily result in more than 200k contacts being returned to this task, which often consumes PHP's memory_limit. Examination of the code shows that DB_mysql->simpleQuery() has the ability to use mysql_unbuffered_query() instead of mysql_query(), with the actual behavior determined by the setting of DB_mysql->options['result_buffering']. DB_common (and thus DB_mysql) has the setOption() method to allow for setting this option, but it is not utilized by CRM_Core_DAO. Given that CRM_Core_DAO is the fundamental object used for database interaction within Civi, I'd like to suggest allowing for manipulating DB_mysql->options from within the DAO object.
1) create a setOptions() method for CRM_Core_DAO to allow for setting options within the DB_mysql object. The proper object to be referenced is found in the global $_DB_DATAOBJECT['CONNECTIONS'], indexed by CRM_Core_DAO->_database_dsn_md5.
2) Modify CRM_Core_DAO->executeQuery() to recognize a new parameter. The new parameter should be an array("option_name"=>"option_value"), corresponding to the options available in DB_mysql->options. If the new parameter is populated, executeQuery() should call $dao->setOptions() prior to calling $dao->query().
We like to get core team's thoughts on this change before implementing it in our own code.
Attachments
Issue Links
- supplements
-
CRM-18128 Slow performance on export
-
- Done/Fixed
-
- links to
A couple of notes - although @totten should look at this
1) I'm not clear on how unbuffered helps (although I'm sure I can do some googling on that & edjumicate myself)
2) I did some digging into memory leaks because I saw some odd things & found there is some dao level caching that can act as a memory leak I believe - here are the tests I did - you can see that after 1000 iterations quite different amounts of memory were in use.
https://github.com/eileenmcnaughton/civicrm-core/commit/901799627e6e710a4345332d839036351ea15f4b
I believe the logic is that the DAO caches the results of simple get $dao->find(); queries in memory and only frees them when you do a free or run an update or insert query (which has the same effect) so when iterating through large result sets it may be necessary to free the DAO ($dao->free) between rows.