HydrationPerformanceTest.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. <?php
  2. namespace Doctrine\Tests\ORM\Performance;
  3. require_once __DIR__ . '/../../TestInit.php';
  4. use Doctrine\Tests\Mocks\HydratorMockStatement,
  5. Doctrine\ORM\Query\ResultSetMapping,
  6. Doctrine\ORM\Query;
  7. /**
  8. * Tests to prevent serious performance regressions.
  9. *
  10. * IMPORTANT: Be sure to run these tests withoug xdebug or similar tools that
  11. * seriously degrade performance.
  12. *
  13. * @author robo
  14. * @group performance
  15. */
  16. class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
  17. {
  18. /**
  19. * Times for comparison:
  20. *
  21. * [romanb: 10000 rows => 0.7 seconds]
  22. *
  23. * MAXIMUM TIME: 1 second
  24. */
  25. public function testSimpleQueryScalarHydrationPerformance10000Rows()
  26. {
  27. $rsm = new ResultSetMapping;
  28. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  29. $rsm->addFieldResult('u', 'u__id', 'id');
  30. $rsm->addFieldResult('u', 'u__status', 'status');
  31. $rsm->addFieldResult('u', 'u__username', 'username');
  32. $rsm->addFieldResult('u', 'u__name', 'name');
  33. // Faked result set
  34. $resultSet = array(
  35. //row1
  36. array(
  37. 'u__id' => '1',
  38. 'u__status' => 'developer',
  39. 'u__username' => 'romanb',
  40. 'u__name' => 'Roman',
  41. ),
  42. array(
  43. 'u__id' => '1',
  44. 'u__status' => 'developer',
  45. 'u__username' => 'romanb',
  46. 'u__name' => 'Roman',
  47. ),
  48. array(
  49. 'u__id' => '2',
  50. 'u__status' => 'developer',
  51. 'u__username' => 'romanb',
  52. 'u__name' => 'Roman',
  53. )
  54. );
  55. for ($i = 4; $i < 10000; ++$i) {
  56. $resultSet[] = array(
  57. 'u__id' => $i,
  58. 'u__status' => 'developer',
  59. 'u__username' => 'jwage',
  60. 'u__name' => 'Jonathan',
  61. );
  62. }
  63. $stmt = new HydratorMockStatement($resultSet);
  64. $hydrator = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this->_em);
  65. $this->setMaxRunningTime(1);
  66. $s = microtime(true);
  67. $result = $hydrator->hydrateAll($stmt, $rsm);
  68. $e = microtime(true);
  69. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  70. }
  71. /**
  72. * Times for comparison:
  73. *
  74. * [romanb: 10000 rows => 1 second]
  75. *
  76. * MAXIMUM TIME: 2 seconds
  77. */
  78. public function testSimpleQueryArrayHydrationPerformance10000Rows()
  79. {
  80. $rsm = new ResultSetMapping;
  81. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  82. $rsm->addFieldResult('u', 'u__id', 'id');
  83. $rsm->addFieldResult('u', 'u__status', 'status');
  84. $rsm->addFieldResult('u', 'u__username', 'username');
  85. $rsm->addFieldResult('u', 'u__name', 'name');
  86. // Faked result set
  87. $resultSet = array(
  88. //row1
  89. array(
  90. 'u__id' => '1',
  91. 'u__status' => 'developer',
  92. 'u__username' => 'romanb',
  93. 'u__name' => 'Roman',
  94. ),
  95. array(
  96. 'u__id' => '1',
  97. 'u__status' => 'developer',
  98. 'u__username' => 'romanb',
  99. 'u__name' => 'Roman',
  100. ),
  101. array(
  102. 'u__id' => '2',
  103. 'u__status' => 'developer',
  104. 'u__username' => 'romanb',
  105. 'u__name' => 'Roman',
  106. )
  107. );
  108. for ($i = 4; $i < 10000; ++$i) {
  109. $resultSet[] = array(
  110. 'u__id' => $i,
  111. 'u__status' => 'developer',
  112. 'u__username' => 'jwage',
  113. 'u__name' => 'Jonathan',
  114. );
  115. }
  116. $stmt = new HydratorMockStatement($resultSet);
  117. $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
  118. $this->setMaxRunningTime(2);
  119. $s = microtime(true);
  120. $result = $hydrator->hydrateAll($stmt, $rsm);
  121. $e = microtime(true);
  122. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  123. }
  124. /**
  125. * Times for comparison:
  126. *
  127. * [romanb: 10000 rows => 1.4 seconds]
  128. *
  129. * MAXIMUM TIME: 3 seconds
  130. */
  131. public function testMixedQueryFetchJoinArrayHydrationPerformance10000Rows()
  132. {
  133. $rsm = new ResultSetMapping;
  134. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  135. $rsm->addJoinedEntityResult(
  136. 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
  137. 'p',
  138. 'u',
  139. 'phonenumbers'
  140. );
  141. $rsm->addFieldResult('u', 'u__id', 'id');
  142. $rsm->addFieldResult('u', 'u__status', 'status');
  143. $rsm->addFieldResult('u', 'u__username', 'username');
  144. $rsm->addFieldResult('u', 'u__name', 'name');
  145. $rsm->addScalarResult('sclr0', 'nameUpper');
  146. $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
  147. // Faked result set
  148. $resultSet = array(
  149. //row1
  150. array(
  151. 'u__id' => '1',
  152. 'u__status' => 'developer',
  153. 'u__username' => 'romanb',
  154. 'u__name' => 'Roman',
  155. 'sclr0' => 'ROMANB',
  156. 'p__phonenumber' => '42',
  157. ),
  158. array(
  159. 'u__id' => '1',
  160. 'u__status' => 'developer',
  161. 'u__username' => 'romanb',
  162. 'u__name' => 'Roman',
  163. 'sclr0' => 'ROMANB',
  164. 'p__phonenumber' => '43',
  165. ),
  166. array(
  167. 'u__id' => '2',
  168. 'u__status' => 'developer',
  169. 'u__username' => 'romanb',
  170. 'u__name' => 'Roman',
  171. 'sclr0' => 'JWAGE',
  172. 'p__phonenumber' => '91'
  173. )
  174. );
  175. for ($i = 4; $i < 10000; ++$i) {
  176. $resultSet[] = array(
  177. 'u__id' => $i,
  178. 'u__status' => 'developer',
  179. 'u__username' => 'jwage',
  180. 'u__name' => 'Jonathan',
  181. 'sclr0' => 'JWAGE' . $i,
  182. 'p__phonenumber' => '91'
  183. );
  184. }
  185. $stmt = new HydratorMockStatement($resultSet);
  186. $hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
  187. $this->setMaxRunningTime(3);
  188. $s = microtime(true);
  189. $result = $hydrator->hydrateAll($stmt, $rsm);
  190. $e = microtime(true);
  191. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  192. }
  193. /**
  194. * [romanb: 10000 rows => 1.5 seconds]
  195. *
  196. * MAXIMUM TIME: 3 seconds
  197. */
  198. public function testSimpleQueryPartialObjectHydrationPerformance10000Rows()
  199. {
  200. $rsm = new ResultSetMapping;
  201. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  202. $rsm->addFieldResult('u', 'u__id', 'id');
  203. $rsm->addFieldResult('u', 'u__status', 'status');
  204. $rsm->addFieldResult('u', 'u__username', 'username');
  205. $rsm->addFieldResult('u', 'u__name', 'name');
  206. // Faked result set
  207. $resultSet = array(
  208. //row1
  209. array(
  210. 'u__id' => '1',
  211. 'u__status' => 'developer',
  212. 'u__username' => 'romanb',
  213. 'u__name' => 'Roman',
  214. ),
  215. array(
  216. 'u__id' => '1',
  217. 'u__status' => 'developer',
  218. 'u__username' => 'romanb',
  219. 'u__name' => 'Roman',
  220. ),
  221. array(
  222. 'u__id' => '2',
  223. 'u__status' => 'developer',
  224. 'u__username' => 'romanb',
  225. 'u__name' => 'Roman',
  226. )
  227. );
  228. for ($i = 4; $i < 10000; ++$i) {
  229. $resultSet[] = array(
  230. 'u__id' => $i,
  231. 'u__status' => 'developer',
  232. 'u__username' => 'jwage',
  233. 'u__name' => 'Jonathan',
  234. );
  235. }
  236. $stmt = new HydratorMockStatement($resultSet);
  237. $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
  238. $this->setMaxRunningTime(3);
  239. $s = microtime(true);
  240. $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
  241. $e = microtime(true);
  242. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  243. }
  244. /**
  245. * [romanb: 10000 rows => 3 seconds]
  246. *
  247. * MAXIMUM TIME: 4.5 seconds
  248. */
  249. public function testSimpleQueryFullObjectHydrationPerformance10000Rows()
  250. {
  251. $rsm = new ResultSetMapping;
  252. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  253. $rsm->addFieldResult('u', 'u__id', 'id');
  254. $rsm->addFieldResult('u', 'u__status', 'status');
  255. $rsm->addFieldResult('u', 'u__username', 'username');
  256. $rsm->addFieldResult('u', 'u__name', 'name');
  257. $rsm->addJoinedEntityResult(
  258. 'Doctrine\Tests\Models\CMS\CmsAddress',
  259. 'a',
  260. 'u',
  261. 'address'
  262. );
  263. $rsm->addFieldResult('a', 'a__id', 'id');
  264. //$rsm->addFieldResult('a', 'a__country', 'country');
  265. //$rsm->addFieldResult('a', 'a__zip', 'zip');
  266. //$rsm->addFieldResult('a', 'a__city', 'city');
  267. // Faked result set
  268. $resultSet = array(
  269. //row1
  270. array(
  271. 'u__id' => '1',
  272. 'u__status' => 'developer',
  273. 'u__username' => 'romanb',
  274. 'u__name' => 'Roman',
  275. 'a__id' => '1'
  276. )
  277. );
  278. for ($i = 2; $i < 10000; ++$i) {
  279. $resultSet[] = array(
  280. 'u__id' => $i,
  281. 'u__status' => 'developer',
  282. 'u__username' => 'jwage',
  283. 'u__name' => 'Jonathan',
  284. 'a__id' => $i
  285. );
  286. }
  287. $stmt = new HydratorMockStatement($resultSet);
  288. $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
  289. $this->setMaxRunningTime(5);
  290. $s = microtime(true);
  291. $result = $hydrator->hydrateAll($stmt, $rsm);
  292. $e = microtime(true);
  293. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  294. }
  295. /**
  296. * [romanb: 2000 rows => 0.4 seconds]
  297. *
  298. * MAXIMUM TIME: 1 second
  299. */
  300. public function testMixedQueryFetchJoinPartialObjectHydrationPerformance2000Rows()
  301. {
  302. $rsm = new ResultSetMapping;
  303. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  304. $rsm->addJoinedEntityResult(
  305. 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
  306. 'p',
  307. 'u',
  308. 'phonenumbers'
  309. );
  310. $rsm->addFieldResult('u', 'u__id', 'id');
  311. $rsm->addFieldResult('u', 'u__status', 'status');
  312. $rsm->addFieldResult('u', 'u__username', 'username');
  313. $rsm->addFieldResult('u', 'u__name', 'name');
  314. $rsm->addScalarResult('sclr0', 'nameUpper');
  315. $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
  316. // Faked result set
  317. $resultSet = array(
  318. //row1
  319. array(
  320. 'u__id' => '1',
  321. 'u__status' => 'developer',
  322. 'u__username' => 'romanb',
  323. 'u__name' => 'Roman',
  324. 'sclr0' => 'ROMANB',
  325. 'p__phonenumber' => '42',
  326. ),
  327. array(
  328. 'u__id' => '1',
  329. 'u__status' => 'developer',
  330. 'u__username' => 'romanb',
  331. 'u__name' => 'Roman',
  332. 'sclr0' => 'ROMANB',
  333. 'p__phonenumber' => '43',
  334. ),
  335. array(
  336. 'u__id' => '2',
  337. 'u__status' => 'developer',
  338. 'u__username' => 'romanb',
  339. 'u__name' => 'Roman',
  340. 'sclr0' => 'JWAGE',
  341. 'p__phonenumber' => '91'
  342. )
  343. );
  344. for ($i = 4; $i < 2000; ++$i) {
  345. $resultSet[] = array(
  346. 'u__id' => $i,
  347. 'u__status' => 'developer',
  348. 'u__username' => 'jwage',
  349. 'u__name' => 'Jonathan',
  350. 'sclr0' => 'JWAGE' . $i,
  351. 'p__phonenumber' => '91'
  352. );
  353. }
  354. $stmt = new HydratorMockStatement($resultSet);
  355. $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
  356. $this->setMaxRunningTime(1);
  357. $s = microtime(true);
  358. $result = $hydrator->hydrateAll($stmt, $rsm, array(Query::HINT_FORCE_PARTIAL_LOAD => true));
  359. $e = microtime(true);
  360. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  361. }
  362. /**
  363. * [romanb: 2000 rows => 0.6 seconds]
  364. *
  365. * MAXIMUM TIME: 1 second
  366. */
  367. public function testMixedQueryFetchJoinFullObjectHydrationPerformance2000Rows()
  368. {
  369. $rsm = new ResultSetMapping;
  370. $rsm->addEntityResult('Doctrine\Tests\Models\CMS\CmsUser', 'u');
  371. $rsm->addJoinedEntityResult(
  372. 'Doctrine\Tests\Models\CMS\CmsPhonenumber',
  373. 'p',
  374. 'u',
  375. 'phonenumbers'
  376. );
  377. $rsm->addFieldResult('u', 'u__id', 'id');
  378. $rsm->addFieldResult('u', 'u__status', 'status');
  379. $rsm->addFieldResult('u', 'u__username', 'username');
  380. $rsm->addFieldResult('u', 'u__name', 'name');
  381. $rsm->addScalarResult('sclr0', 'nameUpper');
  382. $rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
  383. $rsm->addJoinedEntityResult(
  384. 'Doctrine\Tests\Models\CMS\CmsAddress',
  385. 'a',
  386. 'u',
  387. 'address'
  388. );
  389. $rsm->addFieldResult('a', 'a__id', 'id');
  390. // Faked result set
  391. $resultSet = array(
  392. //row1
  393. array(
  394. 'u__id' => '1',
  395. 'u__status' => 'developer',
  396. 'u__username' => 'romanb',
  397. 'u__name' => 'Roman',
  398. 'sclr0' => 'ROMANB',
  399. 'p__phonenumber' => '42',
  400. 'a__id' => '1'
  401. )
  402. );
  403. for ($i = 2; $i < 2000; ++$i) {
  404. $resultSet[] = array(
  405. 'u__id' => $i,
  406. 'u__status' => 'developer',
  407. 'u__username' => 'jwage',
  408. 'u__name' => 'Jonathan',
  409. 'sclr0' => 'JWAGE' . $i,
  410. 'p__phonenumber' => '91',
  411. 'a__id' => $i
  412. );
  413. }
  414. $stmt = new HydratorMockStatement($resultSet);
  415. $hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
  416. $this->setMaxRunningTime(1);
  417. $s = microtime(true);
  418. $result = $hydrator->hydrateAll($stmt, $rsm);
  419. $e = microtime(true);
  420. echo __FUNCTION__ . " - " . ($e - $s) . " seconds" . PHP_EOL;
  421. }
  422. }