@@ -55,17 +55,10 @@ public static function &getFields() {
55
55
* @param $query
56
56
*/
57
57
public static function select (&$ query ) {
58
- // if Mailing mode add mailing id
59
58
if ($ query ->_mode & CRM_Contact_BAO_Query::MODE_MAILING ) {
60
59
$ query ->_select ['mailing_id ' ] = "civicrm_mailing.id as mailing_id " ;
61
60
$ query ->_element ['mailing_id ' ] = 1 ;
62
61
63
- // base table is contact, so join recipients to it
64
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ]
65
- = " INNER JOIN civicrm_mailing_recipients ON civicrm_mailing_recipients.contact_id = contact_a.id " ;
66
-
67
- $ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
68
-
69
62
// get mailing name
70
63
if (!empty ($ query ->_returnProperties ['mailing_name ' ])) {
71
64
$ query ->_select ['mailing_name ' ] = "civicrm_mailing.name as mailing_name " ;
@@ -80,50 +73,47 @@ public static function select(&$query) {
80
73
81
74
// get mailing status
82
75
if (!empty ($ query ->_returnProperties ['mailing_job_status ' ])) {
83
- $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ]
84
- = " LEFT JOIN civicrm_mailing_job ON civicrm_mailing_job.mailing_id = civicrm_mailing.id AND civicrm_mailing_job.parent_id IS NULL AND civicrm_mailing_job.is_test != 1 " ;
85
76
$ query ->_select ['mailing_job_status ' ] = "civicrm_mailing_job.status as mailing_job_status " ;
86
77
$ query ->_element ['mailing_job_status ' ] = 1 ;
87
78
}
88
79
89
- // get email on hold
80
+ // get email on hold - only include if needed
90
81
if (!empty ($ query ->_returnProperties ['email_on_hold ' ])) {
91
82
$ query ->_select ['email_on_hold ' ] = "recipient_email.on_hold as email_on_hold " ;
92
83
$ query ->_element ['email_on_hold ' ] = 1 ;
93
84
$ query ->_tables ['recipient_email ' ] = $ query ->_whereTables ['recipient_email ' ] = 1 ;
94
85
}
95
86
96
- // get recipient email
87
+ // get recipient email - only include if needed
97
88
if (!empty ($ query ->_returnProperties ['email ' ])) {
98
89
$ query ->_select ['email ' ] = "recipient_email.email as email " ;
99
90
$ query ->_element ['email ' ] = 1 ;
100
91
$ query ->_tables ['recipient_email ' ] = $ query ->_whereTables ['recipient_email ' ] = 1 ;
101
92
}
102
93
103
- // get user opt out
94
+ // get user opt out - direct from contact table
104
95
if (!empty ($ query ->_returnProperties ['contact_opt_out ' ])) {
105
96
$ query ->_select ['contact_opt_out ' ] = "contact_a.is_opt_out as contact_opt_out " ;
106
97
$ query ->_element ['contact_opt_out ' ] = 1 ;
107
98
}
108
99
109
100
// mailing job end date / completed date
110
101
if (!empty ($ query ->_returnProperties ['mailing_job_end_date ' ])) {
111
- $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ]
112
- = " LEFT JOIN civicrm_mailing_job ON civicrm_mailing_job.mailing_id = civicrm_mailing.id AND civicrm_mailing_job.parent_id IS NULL AND civicrm_mailing_job.is_test != 1 " ;
113
102
$ query ->_select ['mailing_job_end_date ' ] = "civicrm_mailing_job.end_date as mailing_job_end_date " ;
114
103
$ query ->_element ['mailing_job_end_date ' ] = 1 ;
115
104
}
116
105
106
+ // Only add mailing recipients ID if specifically requested
117
107
if (!empty ($ query ->_returnProperties ['mailing_recipients_id ' ])) {
118
108
$ query ->_select ['mailing_recipients_id ' ] = " civicrm_mailing_recipients.id as mailing_recipients_id " ;
119
109
$ query ->_element ['mailing_recipients_id ' ] = 1 ;
120
110
}
121
- }
122
111
123
- if (CRM_Utils_Array::value ('mailing_campaign_id ' , $ query ->_returnProperties )) {
124
- $ query ->_select ['mailing_campaign_id ' ] = 'civicrm_mailing.campaign_id as mailing_campaign_id ' ;
125
- $ query ->_element ['mailing_campaign_id ' ] = 1 ;
126
- $ query ->_tables ['civicrm_campaign ' ] = 1 ;
112
+ if (CRM_Utils_Array::value ('mailing_campaign_id ' , $ query ->_returnProperties )) {
113
+ $ query ->_select ['mailing_campaign_id ' ] = 'civicrm_mailing.campaign_id as mailing_campaign_id ' ;
114
+ $ query ->_element ['mailing_campaign_id ' ] = 1 ;
115
+ $ query ->_tables ['civicrm_campaign ' ] = 1 ;
116
+ }
127
117
}
128
118
}
129
119
@@ -143,7 +133,6 @@ public static function where(&$query) {
143
133
}
144
134
$ grouping = $ query ->_params [$ id ][3 ];
145
135
self ::whereClauseSingle ($ query ->_params [$ id ], $ query );
146
-
147
136
if (!$ excluded ) {
148
137
// refs #33948, restrict hidden mailing report
149
138
$ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
@@ -175,18 +164,17 @@ public static function from($name, $mode, $side) {
175
164
break ;
176
165
177
166
case 'civicrm_mailing_event_queue ' :
178
- // this is tightly binded so as to do a check WRT actual job recipients ('child' type jobs)
179
- $ from = " INNER JOIN civicrm_mailing_event_queue ON
180
- civicrm_mailing_event_queue.contact_id = civicrm_mailing_recipients.contact_id
181
- AND civicrm_mailing_event_queue.job_id = civicrm_mailing_job.id AND civicrm_mailing_job.job_type = 'child' " ;
167
+ // Add a direct join to contact rather than going through recipients when possible
168
+ $ from = " INNER JOIN civicrm_mailing_event_queue ON civicrm_mailing_event_queue.contact_id = contact_a.id " ;
182
169
break ;
183
170
184
171
case 'civicrm_mailing ' :
185
- $ from = " $ side JOIN civicrm_mailing ON civicrm_mailing.id = civicrm_mailing_recipients.mailing_id " ;
172
+ // Optimize the join by directly connecting to mailing job when possible
173
+ $ from = " $ side JOIN civicrm_mailing ON civicrm_mailing.id = civicrm_mailing_job.mailing_id AND civicrm_mailing.is_hidden = 0 " ;
186
174
break ;
187
175
188
176
case 'civicrm_mailing_job ' :
189
- $ from = " $ side JOIN civicrm_mailing_job ON civicrm_mailing_job.mailing_id = civicrm_mailing .id AND civicrm_mailing_job.is_test != 1 " ;
177
+ $ from = " $ side JOIN civicrm_mailing_job ON civicrm_mailing_event_queue.job_id = civicrm_mailing_job .id AND civicrm_mailing_job.is_test != 1 and civicrm_mailing_job.job_type = 'child' " ;
190
178
break ;
191
179
192
180
case 'civicrm_mailing_event_bounce ' :
@@ -196,17 +184,18 @@ public static function from($name, $mode, $side) {
196
184
case 'civicrm_mailing_event_unsubscribe ' :
197
185
case 'civicrm_mailing_event_forward ' :
198
186
case 'civicrm_mailing_event_trackable_url_open ' :
199
- $ from = " $ side JOIN $ name ON $ name.event_queue_id = civicrm_mailing_event_queue.id " ;
187
+ // Use LEFT JOIN for better performance on "NOT IN" type queries
188
+ $ joinType = ($ side == 'LEFT ' || strpos ($ name , '_delivered ' ) !== false ) ? 'LEFT ' : $ side ;
189
+ $ from = " $ joinType JOIN $ name ON $ name.event_queue_id = civicrm_mailing_event_queue.id " ;
200
190
break ;
201
191
202
192
case 'recipient_email ' :
203
- $ from = " $ side JOIN civicrm_email recipient_email ON recipient_email.id = civicrm_mailing_recipients .email_id " ;
193
+ $ from = " $ side JOIN civicrm_email recipient_email ON recipient_email.id = civicrm_mailing_event_queue .email_id " ;
204
194
break ;
205
195
206
196
case 'civicrm_mailing_trackable_url ' :
207
197
$ from = " $ side JOIN civicrm_mailing_trackable_url ON civicrm_mailing_trackable_url.id = civicrm_mailing_event_trackable_url_open.trackable_url_id " ;
208
198
break ;
209
-
210
199
}
211
200
212
201
return $ from ;
@@ -268,8 +257,9 @@ public static function whereClauseSingle(&$values, &$query) {
268
257
$ selectedMailings = CRM_Utils_Array::implode (' ' .ts ('or ' ).' ' , $ selectedMailings );
269
258
270
259
$ query ->_qill [$ grouping ][] = ts ("Mailing Name " )." - \"$ selectedMailings \"" ;
260
+ $ query ->_tables ['civicrm_mailing_event_queue ' ] = $ query ->_whereTables ['civicrm_mailing_event_queue ' ] = 1 ;
261
+ $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
271
262
$ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
272
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ] = 1 ;
273
263
return ;
274
264
275
265
case 'mailing_name ' :
@@ -280,8 +270,9 @@ public static function whereClauseSingle(&$values, &$query) {
280
270
}
281
271
$ query ->_where [$ grouping ][] = "LOWER(civicrm_mailing.name) $ op ' $ value' " ;
282
272
$ query ->_qill [$ grouping ][] = ts ("Mailing Name " )." - \"$ value \"" ;
273
+ $ query ->_tables ['civicrm_mailing_event_queue ' ] = $ query ->_whereTables ['civicrm_mailing_event_queue ' ] = 1 ;
274
+ $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
283
275
$ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
284
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ] = 1 ;
285
276
return ;
286
277
287
278
case 'mailing_date_low ' :
@@ -303,9 +294,16 @@ public static function whereClauseSingle(&$values, &$query) {
303
294
}
304
295
}
305
296
if (!empty ($ subWhere )) {
306
- $ subQuery = "SELECT cmj.mailing_id FROM civicrm_mailing_job as cmj WHERE cmj.is_test != 1 AND cmj.parent_id IS NULL AND " .implode (' AND ' , $ subWhere )." GROUP BY mailing_id " ;
307
- $ query ->_where [$ grouping ]['mailing_date ' ] = "civicrm_mailing_recipients.mailing_id IN ( $ subQuery) " ;
308
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ] = 1 ;
297
+ // Use a more efficient subquery approach to filter by mailing date
298
+ $ subQuery = "SELECT cmj.mailing_id FROM civicrm_mailing_job as cmj WHERE cmj.is_test != 1 AND cmj.parent_id IS NULL AND " .implode (' AND ' , $ subWhere )." GROUP BY cmj.mailing_id " ;
299
+
300
+ // Set the query directly on mailing_id for better performance
301
+ $ query ->_where [$ grouping ]['mailing_date ' ] = "civicrm_mailing.id IN ( $ subQuery) " ;
302
+
303
+ // Ensure necessary tables are included
304
+ $ query ->_tables ['civicrm_mailing_event_queue ' ] = $ query ->_whereTables ['civicrm_mailing_event_queue ' ] = 1 ;
305
+ $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
306
+ $ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
309
307
}
310
308
return ;
311
309
@@ -317,7 +315,7 @@ public static function whereClauseSingle(&$values, &$query) {
317
315
self ::mailingEventQueryBuilder ($ query , $ values ,
318
316
'civicrm_mailing_event_delivered ' ,
319
317
'mailing_delivery_status ' ,
320
- ts ('Mailing Delivery ' ),
318
+ ts ('Delivery Status ' ),
321
319
$ options
322
320
);
323
321
}
@@ -327,7 +325,7 @@ public static function whereClauseSingle(&$values, &$query) {
327
325
self ::mailingEventQueryBuilder ($ query , $ values ,
328
326
'civicrm_mailing_event_bounce ' ,
329
327
'mailing_delivery_status ' ,
330
- ts ('Mailing Delivery ' ),
328
+ ts ('Delivery Status ' ),
331
329
$ options
332
330
);
333
331
}
@@ -364,10 +362,9 @@ public static function whereClauseSingle(&$values, &$query) {
364
362
$ query ->_where [$ grouping ][] = "civicrm_mailing_trackable_url.url $ op ' $ value' " ;
365
363
$ query ->_qill [$ grouping ][] = ts ("URL " )." - \"$ value \"" ;
366
364
367
- $ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
368
- $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
369
365
$ query ->_tables ['civicrm_mailing_event_queue ' ] = $ query ->_whereTables ['civicrm_mailing_event_queue ' ] = 1 ;
370
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ] = 1 ;
366
+ $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
367
+ $ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
371
368
$ query ->_tables ['civicrm_mailing_event_trackable_url_open ' ] = $ query ->_whereTables ['civicrm_mailing_event_trackable_url_open ' ] = 1 ;
372
369
$ query ->_tables ['civicrm_mailing_trackable_url ' ] = $ query ->_whereTables ['civicrm_mailing_trackable_url ' ] = 1 ;
373
370
return ;
@@ -413,8 +410,9 @@ public static function whereClauseSingle(&$values, &$query) {
413
410
$ subWhere = array ();
414
411
$ subWhere [] = "cmj.status = ' {$ value }' " ;
415
412
$ subQuery = "SELECT cmj.mailing_id FROM civicrm_mailing_job as cmj WHERE cmj.is_test != 1 AND cmj.parent_id IS NULL AND " .implode (' AND ' , $ subWhere )." GROUP BY mailing_id " ;
416
- $ query ->_where [$ grouping ]['mailing_job_status ' ] = "civicrm_mailing_recipients.mailing_id IN ( $ subQuery) " ;
417
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ] = 1 ;
413
+ $ query ->_where [$ grouping ]['mailing_job_status ' ] = "civicrm_mailing_job.mailing_id IN ( $ subQuery) " ;
414
+ $ query ->_tables ['civicrm_mailing_event_queue ' ] = $ query ->_whereTables ['civicrm_mailing_event_queue ' ] = 1 ;
415
+ $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
418
416
419
417
$ query ->_qill [$ grouping ][] = ts ("Mailing Status " )." - " .ts ($ value );
420
418
}
@@ -507,10 +505,14 @@ public static function mailingEventQueryBuilder(&$query, &$values, $tableName, $
507
505
}
508
506
509
507
if ($ value == 'Y ' ) {
510
- $ query ->_where [$ grouping ][] = $ tableName . ".id is not null " ;
508
+ // Use EXISTS subquery for better performance with delivery status
509
+ $ subquery = "EXISTS (SELECT 1 FROM $ tableName WHERE $ tableName.event_queue_id = civicrm_mailing_event_queue.id) " ;
510
+ $ query ->_where [$ grouping ][] = $ subquery ;
511
511
}
512
512
elseif ($ value == 'N ' ) {
513
- $ query ->_where [$ grouping ][] = $ tableName . ".id is null " ;
513
+ // Use NOT EXISTS subquery for better performance with delivery status
514
+ $ subquery = "NOT EXISTS (SELECT 1 FROM $ tableName WHERE $ tableName.event_queue_id = civicrm_mailing_event_queue.id) " ;
515
+ $ query ->_where [$ grouping ][] = $ subquery ;
514
516
}
515
517
516
518
if (is_array ($ value )) {
@@ -521,10 +523,12 @@ public static function mailingEventQueryBuilder(&$query, &$values, $tableName, $
521
523
$ query ->_qill [$ grouping ][] = $ fieldTitle . ' - ' . $ valueTitles [$ value ];
522
524
}
523
525
524
- $ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
525
- $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
526
+ // Always include these required tables
526
527
$ query ->_tables ['civicrm_mailing_event_queue ' ] = $ query ->_whereTables ['civicrm_mailing_event_queue ' ] = 1 ;
527
- $ query ->_tables ['civicrm_mailing_recipients ' ] = $ query ->_whereTables ['civicrm_mailing_recipients ' ] = 1 ;
528
+ $ query ->_tables ['civicrm_mailing_job ' ] = $ query ->_whereTables ['civicrm_mailing_job ' ] = 1 ;
529
+ $ query ->_tables ['civicrm_mailing ' ] = $ query ->_whereTables ['civicrm_mailing ' ] = 1 ;
530
+
531
+ // Include the specific event table
528
532
$ query ->_tables [$ tableName ] = $ query ->_whereTables [$ tableName ] = 1 ;
529
533
}
530
534
0 commit comments