我在Azure上提供了Laravel应用。我正在使用AJAX请求来轮询JavaScript图表的数据。
AJAX请求在我的路线(web.php)中定义的URL,因此:
Route::get('/rfp_chart_data', 'DataController@chart_data')->name('chart_data');
该控制器方法运行一个PostgreSQL查询并返回一个JSON文件。一切正常。
但是,在遇到一些性能问题后,我决定监视postgres查询,并发现对该URL的每个请求相同的查询正在运行3次。
无论我是否这样做,都会发生这种情况
通过AJAX请求访问URL
直接进入浏览器中的URL
通过cURL访问URL
此(AFAIK)消除了这是某种缺少的img src问题(例如What can cause a double page request?)的可能性
非常感谢您的帮助...
编辑:
postgres pg_stat_activity中重复查询的图像-来自1个Web请求:
编辑:
完整的控制器代码:
<?php
namespace App\Http\Controllers;
use App\AllRfpEntry;
use DB;
use Illuminate\Http\Request;
use Yajra\Datatables\Facades\Datatables;
class DataController extends Controller {
/**
* Displays datatables front end view
*
* @return \Illuminate\View\View
*/
//|| result_url || '\">' || result_title || '</a>'
public function chart_data(Request $request) {
$binding_array = array();
$chart_data_sql = "SELECT relevant_dates.date::date,
CASE WHEN award_totals.sum IS NULL
THEN 0
ELSE award_totals.sum
END
as sum
,
CASE WHEN award_totals.transaction_count IS NULL
THEN 0
ELSE award_totals.transaction_count
END
as transaction_count FROM
(
SELECT * FROM generate_series('" . date('Y-m-01', strtotime('-15 month')) . "'::date, '" . date('Y-m-01') . "'::date, '1 month') AS date
) relevant_dates
LEFT JOIN
(
SELECT extract(year from awarded_date)::text || '-' || RIGHT('0' || extract(month from awarded_date)::text, 2) || '-01' as date, sum(award_amount)::numeric as sum, COUNT(award_amount) as transaction_count FROM all_rfp_entries
WHERE awarded_date >= '" . date('Y-m-01', strtotime('-15 month')) . "'
AND awarded_date <= '" . date("Y-m-d") . "' AND award_status = 'AWARDED'
AND award_amount::numeric < 10000000000";
if ($request->get('rfp_company_filter')) {
$binding_array['rfp_company_filter'] = $request->get('rfp_company_filter');
$chart_data_sql .= " AND company = :rfp_company_filter";
};
if ($request->get('rfp_source_filter')) {
$binding_array['rfp_source_filter'] = $request->get('rfp_source_filter');
$chart_data_sql .= " AND rfp_source = :rfp_source_filter";
}
if ($request->get('exclude_fed_rev')) {
$chart_data_sql .= " AND rfp_source != 'US FED REV' ";
}
if ($request->get('rfp_year_filter')) {
$binding_array['rfp_year_filter'] = $request->get('rfp_year_filter');
$chart_data_sql .= " AND year = :rfp_year_filter";
}
if ($request->get('rfp_priority_level_filter')) {
$binding_array['rfp_priority_level_filter'] = $request->get('rfp_priority_level_filter');
$chart_data_sql .= " AND priority_level = :rfp_priority_level_filter";
}
if ($request->get('rfp_search_input_chart')) {
$binding_array['rfp_search_input_chart'] = $request->get('rfp_search_input_chart');
$chart_data_sql .= " AND search_document::tsvector @@ plainto_tsquery('simple', :rfp_search_input_chart)";
}
$chart_data_sql .= " GROUP BY extract(year from awarded_date), extract(month from awarded_date)
) award_totals
on award_totals.date::date = relevant_dates.date::date
ORDER BY extract(year from relevant_dates.date::date), extract(month from relevant_dates.date::date)
";
return json_encode(DB::select($chart_data_sql, $binding_array));
}
public function data(Request $request) {
$query = AllRfpEntry::select('id', 'year', 'company', 'result_title', 'award_amount', 'edit_column', 'doc_type', 'rfp_source', 'posted_date', 'awarded_date', 'award_status', 'priority_level', 'word_score', 'summary', 'contract_age', 'search_document', 'link');
if ($request->get('exclude_na')) {
$query->where('all_rfp_entries.company', '!=', 'NA');
}
if ($request->get('clicked_date')) {
$query->where('all_rfp_entries.awarded_date', '>', $request->get('clicked_date'));
$query->where('all_rfp_entries.awarded_date', '<=', $request->get('clicked_date_plus_one_month'));
}
if ($request->get('filter_input')) {
$query->whereRaw("search_document::tsvector @@ plainto_tsquery('simple', '" . $request->get('filter_input') . "')");
}
$datatables_json = datatables()->of($query)
->rawColumns(['result_title', 'edit_column', 'link'])
->orderColumn('award_amount', 'award_amount $1 NULLS LAST')
->orderColumn('priority_level', 'priority_level $1 NULLS LAST');
if (!$request->get('filter_input')) {
$datatables_json = $datatables_json->orderByNullsLast();
}
if (!$request->get('filter_input') and !$request->get('clicked_date')) {
$count_table = 'all_rfp_entries';
$count = DB::select(DB::raw("SELECT n_live_tup FROM pg_stat_all_tables WHERE relname = :count_table "), array('count_table' => $count_table))[0]->n_live_tup;
$datatables_json = $datatables_json->setTotalRecords($count);
}
$datatables_json = $datatables_json->make(true);
return $datatables_json;
}
}
编辑:
甚至更疯狂的皱纹...
我在该服务器上的Laravel中有一个方法指向另一个服务器上的postgres数据库,以吸收新数据。我刚刚发现,即使那个THAT方法(一个指向外部服务器的方法)也在外部postgres服务器上生成多个查询!
除非我缺少任何内容,否则可以避免nginx问题或提供程序(Azure)的问题,或任何一种特定方法的问题。即使通过端口5432进行的直接数据库连接(我想这是Laravel访问外部数据库的方式)也会产生乘数效应,因此,在我的Laravel安装中这一定有些棘手...但是还无法弄清楚是什么。
答案 0 :(得分:4)
调试此问题的最佳方法是使用xdebug启动调试会话,并逐步执行代码,同时注意单独窗口中的stdout / logging输出。
在控制器的第一行设置一个断点,当断点时,应该完成0个查询。如果不是,您会知道路由/请求中发生了奇怪的事情。然后逐步完成用于构建查询的函数调用。
您使用的函数之一可能会触发执行查询的操作(如Aaron Saray所建议)或方法丢失(如Diogo Gomes所建议),但这很难在不知道代码或不逐步执行的情况下分辨出来上下文逐步介绍。
如果没有调试器,则始终可以在任何行上使用dd($data);
来停止处理并转储给定的数据。这将花费一点时间,因为您将对代码中的每个步骤都进行新的请求。
答案 1 :(得分:0)
对于它的价值,我将其追溯到多个postgres worker进程(您可以在postgres .conf文件中进行设置)。因此,这不是错误,也不是Laravel的问题-仅仅是postgres产生的并行工作者。