-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
添加慢SQL的的优化管理功能 #2549
base: master
Are you sure you want to change the base?
添加慢SQL的的优化管理功能 #2549
Changes from all commits
31365b9
2375d6b
d44a5ff
67ccc2a
d2a56f8
16763da
17f82a8
e65d6fa
a625b55
757755d
0233b2f
1a6dc00
2eb0547
313aa95
5b99511
b4e2951
e9b4584
0c63dcb
5f3b55b
782ec55
647b4b8
1240025
962c2da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,4 @@ pytest-django | |
pytest-mock | ||
pytest-cov | ||
codecov | ||
flake8 | ||
flake8 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,4 +25,4 @@ omit = [ | |
# omit this single file | ||
"sql/migrations/*", | ||
"venv*" | ||
] | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,14 +6,17 @@ | |
from django.contrib.auth.decorators import permission_required | ||
from django.db.models import F, Sum, Value as V, Max | ||
from django.db.models.functions import Concat | ||
from django.http import HttpResponse | ||
from django.http import HttpResponse, JsonResponse | ||
from django.views.decorators.cache import cache_page | ||
from pyecharts.charts import Line | ||
from pyecharts import options as opts | ||
from common.utils.chart_dao import ChartDao | ||
from sql.engines import get_engine | ||
|
||
from sql.utils.resource_group import user_instances | ||
from sql.utils.instance_management import ( | ||
SUPPORTED_MANAGEMENT_DB_TYPE, | ||
) | ||
from common.utils.extend_json_encoder import ExtendJSONEncoder | ||
from .models import Instance, SlowQuery, SlowQueryHistory, AliyunRdsConfig | ||
|
||
|
@@ -68,8 +71,22 @@ def slowquery_review(request): | |
fingerprint__icontains=search, | ||
**filter_kwargs | ||
) | ||
.annotate(SQLText=F("fingerprint"), SQLId=F("checksum")) | ||
.values("SQLText", "SQLId") | ||
.annotate( | ||
SQLText=F("fingerprint"), | ||
SQLId=F("checksum"), | ||
ReviewedBy=F("reviewed_by"), | ||
ReviewedOn=F("reviewed_on"), | ||
Comments=F("comments"), | ||
ReviewedStatus=F("reviewed_status"), | ||
) | ||
.values( | ||
"SQLText", | ||
"SQLId", | ||
"ReviewedBy", | ||
"ReviewedOn", | ||
"Comments", | ||
"ReviewedStatus", | ||
) | ||
.annotate( | ||
CreateTime=Max("slowqueryhistory__ts_max"), | ||
DBName=Max("slowqueryhistory__db_max"), # 数据库 | ||
|
@@ -162,6 +179,7 @@ def slowquery_review_history(request): | |
sample__icontains=search, | ||
**filter_kwargs | ||
).annotate( | ||
SQLChecksum=F("checksum"), # SQL语句校验和 | ||
ExecutionStartTime=F( | ||
"ts_min" | ||
), # 本次统计(每5分钟一次)该类型sql语句出现的最小时间 | ||
|
@@ -182,6 +200,7 @@ def slowquery_review_history(request): | |
slow_sql_record_list = slow_sql_record_obj.order_by( | ||
"-" + sortName if "desc".__eq__(sortOrder) else sortName | ||
)[offset:limit].values( | ||
"SQLChecksum", | ||
"ExecutionStartTime", | ||
"DBName", | ||
"HostAddress", | ||
|
@@ -251,3 +270,47 @@ def report(request): | |
|
||
result = {"status": 0, "msg": "", "data": line.render_embed()} | ||
return HttpResponse(json.dumps(result), content_type="application/json") | ||
|
||
|
||
@permission_required("sql.menu_slowquery", raise_exception=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 沿用查看慢日志的权限,没有单独加权限控制,后续可以添加。 |
||
def listreview(request): | ||
"""获取优化详情""" | ||
checksum = request.POST.get("review_checksum") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 获取用户在页面中勾选的SQL语句对应的checksum |
||
if not checksum: | ||
return JsonResponse({"status": 0, "msg": "Checksum获取失败", "data": []}) | ||
review_details = SlowQuery.objects.filter(checksum=checksum).values( | ||
"checksum", "reviewed_by", "reviewed_on", "comments", "reviewed_status" | ||
) | ||
rows = [row for row in review_details] | ||
if not rows: | ||
result = {"status": 1, "msg": "优化详情获取失败"} | ||
else: | ||
result = {"status": 0, "msg": "ok", "rows": rows} | ||
return HttpResponse( | ||
json.dumps(result, cls=ExtendJSONEncoder, bigint_as_string=True), | ||
content_type="application/json", | ||
) | ||
|
||
|
||
@permission_required("sql.menu_slowquery", raise_exception=True) | ||
def editreview(request): | ||
"""更新优化详情""" | ||
checksum = request.POST.get("checksum") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 获取欲操作的SQL语句对应的checksum There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 编辑框传过来的值 |
||
reviewed_by = request.POST.get("reviewed_by", "") | ||
reviewed_on = request.POST.get("reviewed_on", "") | ||
comments = request.POST.get("comments", "") | ||
reviewed_status = request.POST.get("reviewed_status", "") | ||
if not all([checksum, reviewed_by, reviewed_on, comments, reviewed_status]): | ||
return JsonResponse( | ||
{"status": 1, "msg": "参数不完整,请确认后提交", "data": []} | ||
) | ||
record = SlowQuery.objects.filter(checksum=checksum) | ||
if not record: | ||
return JsonResponse({"status": 1, "msg": "记录不存在", "data": []}) | ||
record.update( | ||
reviewed_by=reviewed_by, | ||
reviewed_on=reviewed_on, | ||
comments=comments, | ||
reviewed_status=reviewed_status, | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 更新数据库 |
||
return JsonResponse({"status": 0, "msg": "", "data": []}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
{% extends "base.html" %} | ||
|
||
|
||
|
||
|
||
{% block content %} | ||
|
||
<!-- 表格--> | ||
<div class="table-responsive"> | ||
<table id="user-list" data-toggle="table" class="table table-striped table-hover" | ||
style="table-layout:inherit;overflow:hidden;text-overflow:ellipsis;"> | ||
</table> | ||
</div> | ||
<!-- 修改密码模态框 --> | ||
<div class="modal fade" id="edit-review" tabindex="-1" role="dialog"> | ||
<div class="modal-dialog" role="document"> | ||
<div class="modal-content"> | ||
<div class="modal-header"> | ||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span | ||
aria-hidden="true">×</span></button> | ||
<h4 class="modal-title">编辑详情</h4> | ||
</div> | ||
<div class="modal-body form-group"> | ||
<div class="form-group row"> | ||
<label for="comments" class="col-sm-3 col-form-label"> | ||
<span style="color:red">*</span>内容</label> | ||
<div class="col-sm-9"> | ||
<input type="text" id="comments" class="form-control" | ||
placeholder="请填写详情"> | ||
</small> | ||
</div> | ||
</div> | ||
<div class="form-group row"> | ||
<label for="reviewed-status" class="col-sm-3 col-form-label"> | ||
<span style="color:red">*</span>状态</label> | ||
<div class="col-sm-9"> | ||
<select id="reviewed-status" name="reviewed-status-name"> | ||
<option value="open">open</option> | ||
<option value="resolved">resolved</option> | ||
<option value="pending">pending</option> | ||
<option value="closed">closed</option> | ||
</select> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="modal-footer"> | ||
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button> | ||
<button type="button" class="btn btn-danger" id="editRevBtn">修改</button> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
{% endblock content %} | ||
{% block js %} | ||
{% load static %} | ||
<script src="{% static 'bootstrap-table/js/bootstrap-table-export.min.js' %}"></script> | ||
<script src="{% static 'bootstrap-table/js/tableExport.min.js' %}"></script> | ||
<script> | ||
//获取优化详情列表 | ||
function review_list() { | ||
var pathname = window.location.pathname; | ||
if (pathname == "/sqlreview/") { | ||
var review_checksum = sessionStorage.getItem('review_checksum'); | ||
} | ||
//初始化table | ||
$('#user-list').bootstrapTable('destroy').bootstrapTable({ | ||
escape: false, | ||
method: 'post', | ||
contentType: "application/x-www-form-urlencoded", | ||
url: "/sqlreview/list/", | ||
striped: true, //是否显示行间隔色 | ||
cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*) | ||
pagination: true, //是否显示分页(*) | ||
sortable: true, //是否启用排序 | ||
sortOrder: "asc", //排序方式 | ||
sidePagination: "client", //分页方式:client客户端分页,server服务端分页(*) | ||
pageNumber: 1, //初始化加载第一页,默认第一页,并记录 | ||
pageSize: 14, //每页的记录行数(*) | ||
pageList: [20, 30, 50, 100], //可供选择的每页的行数(*) | ||
showExport: true, //是否显示导出按钮 | ||
exportOptions: { | ||
fileName: 'checksum' //文件名称设置 | ||
}, | ||
search: true, //是否显示表格搜索 | ||
strictSearch: false, //是否全匹配搜索 | ||
showColumns: true, //是否显示所有的列(选择显示的列) | ||
showRefresh: true, //是否显示刷新按钮 | ||
minimumCountColumns: 2, //最少允许的列数 | ||
clickToSelect: true, //是否启用点击选中行 | ||
uniqueId: 'checksum', //每一行的唯一标识,一般为主键列 | ||
showToggle: true, //是否显示详细视图和列表视图的切换按钮 | ||
cardView: false, //是否显示详细视图 | ||
detailView: false, //是否显示父子表 | ||
locale: 'zh-CN', //本地化 | ||
toolbar: "#toolbar", //指明自定义的toolbar | ||
queryParamsType: 'limit', | ||
//请求服务数据时所传参数 | ||
queryParams: | ||
function (params) { | ||
if (review_checksum) { | ||
return { | ||
search: params.search, | ||
review_checksum: review_checksum | ||
} | ||
} | ||
}, | ||
columns: [{ | ||
title: 'SQLID', | ||
field: 'checksum' | ||
},{ | ||
title: '优化内容', | ||
field: 'comments', | ||
width: "30", | ||
widthUnit: "%" | ||
},{ | ||
title: '优化状态', | ||
field: 'reviewed_status' | ||
},{ | ||
title: '提交人', | ||
field: 'reviewed_by' | ||
},{ | ||
title: '提交日期', | ||
field: 'reviewed_on' | ||
},{ | ||
title: '操作', | ||
field: '', | ||
formatter: function (value, row, index) { | ||
let btn_edit_review = "<button class=\"btn btn-warning btn-xs\" review_checksum=\"" + row.checksum + "\" onclick=\"review_edit(this)" + "\">编辑</button>\n"; | ||
return btn_edit_review | ||
} | ||
}], | ||
onLoadSuccess: function (data) { | ||
if (data.status !== 0) { | ||
alert("数据加载失败!" + data.msg); | ||
}}, | ||
onLoadError: onLoadErrorCallback, | ||
onSearch: function (e) { | ||
//传搜索参数给服务器 | ||
queryParams(e) | ||
} | ||
}); | ||
|
||
} | ||
|
||
//编辑页面 | ||
function review_edit(obj) { | ||
review_checksum = $(obj).attr("review_checksum"); | ||
user= user; | ||
$("#edit-review").modal('show'); | ||
//编辑详情 | ||
$("#editRevBtn").unbind("click").click(function () { | ||
var dt = new Date(+new Date()+8*3600*1000); | ||
currenttime = dt.toISOString().slice(0, 19).replace('T', ' '); | ||
$.ajax({ | ||
type: "post", | ||
url: "/sqlreview/edit/", | ||
dataType: "json", | ||
data: { | ||
checksum: review_checksum, | ||
reviewed_by: user, | ||
reviewed_on: currenttime, | ||
comments: $("#comments").val(), | ||
reviewed_status: $("#reviewed-status").val(), | ||
}, | ||
complete: function () { | ||
}, | ||
success: function (data) { | ||
if (data.status === 0) { | ||
$('#edit-review').modal('hide'); | ||
$("#edit-review input").val(""); | ||
review_list() | ||
} else { | ||
alert(data.msg); | ||
} | ||
}, | ||
error: function (XMLHttpRequest, textStatus, errorThrown) { | ||
alert(errorThrown); | ||
} | ||
}); | ||
}); | ||
} | ||
//初始化数据 | ||
$(document).ready(function () { | ||
review_list(); | ||
}); | ||
</script> | ||
{% endblock %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个PR中,SQLId, checksum, SQLChecksum实际上都是archery.mysql_slow_query_review表的checksum字段。是为了显示方便所以有不同叫法。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review_checksum也是