Documentation
¶
Overview ¶
Package common contain many useful functions for logging, formatting and so on.
Index ¶
- Variables
- func ArgConfig() string
- func Caller() string
- func Chardet(buf []byte) string
- func CheckCharsetByBOM(buf []byte) string
- func FormatDSN(env *Dsn) string
- func GetDataTypeBase(dataType string) string
- func GetDataTypeLength(dataType string) []int
- func GetFunctionName() string
- func GoldenDiff(f func(), name string, update *bool) error
- func HandleSignal(f func())
- func IsColsPart(a, b []*Column) bool
- func JSONFind(json string, name string) []string
- func JoinColumnsName(cols []*Column, sep string) string
- func ListReportTypes()
- func LogIfError(err error, format string, v ...interface{})
- func LogIfWarn(err error, format string, v ...interface{})
- func LoggerInit()
- func Markdown2HTML(buf string) string
- func MarkdownEscape(str string) string
- func MarkdownHTMLHeader() string
- func ParseConfig(configFile string) error
- func PrintConfiguration()
- func RemoveBOM(buf []byte) (string, []byte)
- func RemoveDuplicatesItem(duplicate []string) []string
- func Score(score int) string
- func SoarVersion()
- func SortedKey(m interface{}) []string
- func StringStorageReq(dataType string, charset string) int
- type Column
- type Configuration
- type DB
- type Dsn
- type KeyType
- type Meta
- type ReportType
- type Table
- type TableColumns
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // BlackList 黑名单中的SQL不会被评审 BlackList []string // PrintConfig -print-config PrintConfig bool // PrintVersion -print-config PrintVersion bool // CheckConfig -check-config CheckConfig bool )
var ( Version = "No Version Provided" Compile = "" Branch = "" GitDirty = "" DevPath = "" )
-version输出信息
var BaseDir string
BaseDir 日志打印在binary的根路径
var BuiltinCSS = `` /* 1851-byte string literal not displayed */
BuiltinCSS 内置HTML风格
var BuiltinJavascript = `` /* 51813-byte string literal not displayed */
BuiltinJavascript 内置 SQL 美化 Javascript 脚本
var CharSets = map[string]int{
"armscii8": 1,
"ascii": 1,
"big5": 2,
"binary": 1,
"cp1250": 1,
"cp1251": 1,
"cp1256": 1,
"cp1257": 1,
"cp850": 1,
"cp852": 1,
"cp866": 1,
"cp932": 2,
"dec8": 1,
"eucjpms": 3,
"euckr": 2,
"gb18030": 4,
"gb2312": 2,
"gbk": 2,
"geostd8": 1,
"greek": 1,
"hebrew": 1,
"hp8": 1,
"keybcs2": 1,
"koi8r": 1,
"koi8u": 1,
"latin1": 1,
"latin2": 1,
"latin5": 1,
"latin7": 1,
"macce": 1,
"macroman": 1,
"sjis": 2,
"swe7": 1,
"tis620": 1,
"ucs2": 2,
"ujis": 3,
"utf16": 4,
"utf16le": 4,
"utf32": 4,
"utf8": 3,
"utf8mb4": 4,
}
CharSets character bytes per charcharacter bytes per char
var Config = &Configuration{ OnlineDSN: newDSN(nil), TestDSN: newDSN(nil), AllowOnlineAsTest: false, DropTestTemporary: true, CleanupTestDatabase: false, DryRun: true, OnlySyntaxCheck: false, SamplingStatisticTarget: 100, Sampling: false, Profiling: false, Trace: false, Explain: true, Delimiter: ";", MinCardinality: 0, MaxJoinTableCount: 5, MaxGroupByColsCount: 5, MaxDistinctCount: 5, MaxIdxColsCount: 5, MaxTextColsCount: 2, MaxIdxBytesPerColumn: 767, MaxIdxBytes: 3072, MaxTotalRows: 9999999, MaxQueryCost: 9999, SpaghettiQueryLength: 2048, AllowDropIndex: false, LogLevel: 3, LogOutput: "soar.log", ReportType: "markdown", ReportCSS: "", ReportJavascript: "", ReportTitle: "SQL优化分析报告", BlackList: "", AllowCharsets: []string{"utf8", "utf8mb4"}, AllowCollates: []string{}, AllowEngines: []string{"innodb"}, MaxIdxCount: 10, MaxColCount: 40, MaxValueCount: 100, MaxInCount: 10, IdxPrefix: "idx_", UkPrefix: "uk_", MaxSubqueryDepth: 5, MaxVarcharLength: 1024, ColumnNotAllowType: []string{"boolean"}, MarkdownExtensions: 94, MarkdownHTMLFlags: 0, ExplainSQLReportType: "pretty", ExplainType: "extended", ExplainFormat: "traditional", ExplainWarnSelectType: []string{""}, ExplainWarnAccessType: []string{"ALL"}, ExplainMaxKeyLength: 3, ExplainMinPossibleKeys: 0, ExplainMaxRows: 10000, ExplainWarnExtra: []string{"Using temporary", "Using filesort"}, ExplainMaxFiltered: 100.0, ExplainWarnScalability: []string{"O(n)"}, ShowWarnings: false, ShowLastQueryCost: false, IgnoreRules: []string{ "COL.011", }, RewriteRules: []string{ "delimiter", "orderbynull", "groupbyconst", "dmlorderby", "having", "star2columns", "insertcolumns", "distinctstar", }, ListHeuristicRules: false, ListRewriteRules: false, ListTestSqls: false, ListReportTypes: false, MaxPrettySQLLength: 1024, }
Config 默认设置
var Log *logs.BeeLogger
Log 使用 beego 的 log 库
var ReportTypes = []ReportType{
{
Name: "lint",
Description: "参考sqlint格式,以插件形式集成到代码编辑器,显示输出更加友好",
Example: `soar -report-type lint -query test.sql`,
},
{
Name: "markdown",
Description: "该格式为默认输出格式,以markdown格式展现,可以用网页浏览器插件直接打开,也可以用markdown编辑器打开",
Example: `echo "select * from film" | soar`,
},
{
Name: "rewrite",
Description: "SQL重写功能,配合-rewrite-rules参数一起使用,可以通过-list-rewrite-rules 查看所有支持的 SQL 重写规则",
Example: `echo "select * from film" | soar -rewrite-rules star2columns,delimiter -report-type rewrite`,
},
{
Name: "ast",
Description: "输出 SQL 的抽象语法树,主要用于测试",
Example: `echo "select * from film" | soar -report-type ast`,
},
{
Name: "ast-json",
Description: "以 JSON 格式输出 SQL 的抽象语法树,主要用于测试",
Example: `echo "select * from film" | soar -report-type ast-json`,
},
{
Name: "tiast",
Description: "输出 SQL 的 TiDB抽象语法树,主要用于测试",
Example: `echo "select * from film" | soar -report-type tiast`,
},
{
Name: "tiast-json",
Description: "以 JSON 格式输出 SQL 的 TiDB抽象语法树,主要用于测试",
Example: `echo "select * from film" | soar -report-type tiast-json`,
},
{
Name: "tables",
Description: "以 JSON 格式输出 SQL 使用的库表名",
Example: `echo "select * from film" | soar -report-type tables`,
},
{
Name: "query-type",
Description: "SQL 语句的请求类型",
Example: `echo "select * from film" | soar -report-type query-type`,
},
{
Name: "fingerprint",
Description: "输出SQL的指纹",
Example: `echo "select * from film where language_id=1" | soar -report-type fingerprint`,
},
{
Name: "md2html",
Description: "markdown 格式转 html 格式小工具",
Example: `soar -list-heuristic-rules | soar -report-type md2html > heuristic_rules.html`,
},
{
Name: "explain-digest",
Description: "输入为EXPLAIN的表格,JSON 或 Vertical格式,对其进行分析,给出分析结果",
Example: `soar -report-type explain-digest << EOF
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | film | ALL | NULL | NULL | NULL | NULL | 1131 | |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
EOF`,
},
{
Name: "duplicate-key-checker",
Description: "对 OnlineDsn 中指定的 database 进行索引重复检查",
Example: `soar -report-type duplicate-key-checker -online-dsn user:password@127.0.0.1:3306/db`,
},
{
Name: "html",
Description: "以HTML格式输出报表",
Example: `echo "select * from film" | soar -report-type html`,
},
{
Name: "json",
Description: "输出JSON格式报表,方便应用程序处理",
Example: `echo "select * from film" | soar -report-type json`,
},
{
Name: "tokenize",
Description: "对SQL进行切词,主要用于测试",
Example: `echo "select * from film" | soar -report-type tokenize`,
},
{
Name: "compress",
Description: "SQL压缩小工具,使用内置SQL压缩逻辑,测试中的功能",
Example: `echo "select
*
from
film" | soar -report-type compress`,
},
{
Name: "pretty",
Description: "使用kr/pretty打印报告,主要用于测试",
Example: `echo "select * from film" | soar -report-type pretty`,
},
{
Name: "remove-comment",
Description: "去除SQL语句中的注释,支持单行多行注释的去除",
Example: `echo "select/*comment*/ * from film" | soar -report-type remove-comment`,
},
{
Name: "chardet",
Description: "猜测输入的 SQL 使用的字符集",
Example: "echo '中文' | soar -report-type chardet",
},
}
ReportTypes 命令行-report-type支持的形式
var TestSQLs []string
TestSQLs 测试SQL大集合
Functions ¶
func Caller ¶
func Caller() string
Caller returns the caller of the function that called it :) https://stackoverflow.com/questions/35212985/is-it-possible-get-information-about-caller-function-in-golang
func CheckCharsetByBOM ¶
CheckCharsetByBOM ref: https://en.wikipedia.org/wiki/Byte_order_mark
func FormatDSN ¶
FormatDSN 格式化打印DSN
Example ¶
Log.Debug("Entering function: %s", GetFunctionName())
dsxExp := newDSN(nil)
dsxExp.Addr = "127.0.0.1:3306"
dsxExp.Schema = "mysql"
dsxExp.User = "root"
dsxExp.Password = "1t'sB1g3rt"
dsxExp.Charset = "utf8mb4"
dsxExp.Disable = false
// 根据 &dsn 生成 dsnStr
fmt.Println(FormatDSN(dsxExp))
Output: root:1t'sB1g3rt@tcp(127.0.0.1:3306)/mysql?timeout=3s&charset=utf8mb4
func GetDataTypeBase ¶
GetDataTypeBase 获取dataType中的数据类型,忽略长度
func GetDataTypeLength ¶
GetDataTypeLength 获取dataType中的数据类型长度
func GoldenDiff ¶
GoldenDiff 从 gofmt 学来的测试方法 https://medium.com/soon-london/testing-with-golden-files-in-go-7fccc71c43d3
func HandleSignal ¶
func HandleSignal(f func())
HandleSignal 当程序卡死的时候,或者由于某些原因程序没有退出,可以通过捕获信号量的形式让程序优雅退出并且清理测试环境
func IsColsPart ¶
IsColsPart 判断两个column队列是否是包含关系(包括相等)
Example ¶
Log.Debug("Entering function: %s", GetFunctionName())
// IsColsPart() 会 按照顺序 检查两个Column队列是否是包含(或相等)关系。
a := []*Column{{Name: "1"}, {Name: "2"}, {Name: "3"}}
b := []*Column{{Name: "1"}, {Name: "2"}}
c := []*Column{{Name: "1"}, {Name: "3"}}
d := []*Column{{Name: "1"}, {Name: "2"}, {Name: "3"}, {Name: "4"}}
id := []*Column{{Name: "id"}}
iD := []*Column{{Name: "iD"}}
ab := IsColsPart(a, b)
ac := IsColsPart(a, c)
ad := IsColsPart(a, d)
idiD := IsColsPart(id, iD) // 大小写对比
fmt.Println(ab, ac, ad, idiD)
Output: true false true true
func JSONFind ¶
JSONFind iterate find name in json TODO: for complicate SQL JSONFind will run a long time for json interactions.
func JoinColumnsName ¶
JoinColumnsName 将所有的列合并
func LogIfError ¶
LogIfError 简化if err != nil 打 Error 日志代码长度
func MarkdownHTMLHeader ¶
func MarkdownHTMLHeader() string
MarkdownHTMLHeader markdown 转 HTML 输出时添加 HTML 头
func RemoveDuplicatesItem ¶
RemoveDuplicatesItem remove duplicate item from list
func SortedKey ¶
func SortedKey(m interface{}) []string
SortedKey sort map[string]interface{}, use in range clause
Example ¶
Log.Debug("Entering function: %s", GetFunctionName())
ages := map[string]int{
"a": 1,
"c": 3,
"d": 4,
"b": 2,
}
for _, name := range SortedKey(ages) {
fmt.Print(ages[name])
}
Output: 1234
func StringStorageReq ¶
StringStorageReq String Type Storage Requirements return bytes count
Types ¶
type Column ¶
type Column struct {
Name string `json:"col_name"` // 列名
Alias []string `json:"alias"` // 别名
Table string `json:"tb_name"` // 表名
DB string `json:"db_name"` // 数据库名称
DataType string `json:"data_type"` // 数据类型
Character string `json:"character"` // 字符集
Collation string `json:"collation"` // collation
Cardinality float64 `json:"cardinality"` // 散粒度
Null string `json:"null"` // 是否为空: YES/NO
Key string `json:"key"` // 键类型
Default string `json:"default"` // 默认值
Extra string `json:"extra"` // 其他
Comment string `json:"comment"` // 备注
Privileges string `json:"privileges"` // 权限
}
Column 含有列的定义属性
func ColumnSort ¶
ColumnSort 通过散粒度对 colList 进行排序, 散粒度排序由大到小
func MergeColumn ¶
MergeColumn 将使用到的列按 db->table 组织去重 注意:Column 中的 db, table 信息可能为空,需要提前通过env环境补齐再调用该函数。 @input: 目标列list, 源列list(可以将多个源合并到一个目标列list) @output: 合并后的列list
func (*Column) GetDataBytes ¶
GetDataBytes 计算数据类型字节数 https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html return -1 表示该列无法计算数据大小
type Configuration ¶
type Configuration struct {
// +++++++++++++++测试环境+++++++++++++++++
OnlineDSN *Dsn `yaml:"online-dsn"` // 线上环境数据库配置
TestDSN *Dsn `yaml:"test-dsn"` // 测试环境数据库配置
AllowOnlineAsTest bool `yaml:"allow-online-as-test"` // 允许 Online 环境也可以当作 Test 环境
DisableVersionCheck bool `yaml:"disable-version-check"` // 是否禁用环境检测,开启后表示允许测试环境版本低于线上环境 不建议开启,可能会导致语句执行异常
DropTestTemporary bool `yaml:"drop-test-temporary"` // 是否清理Test环境产生的临时库表
CleanupTestDatabase bool `yaml:"cleanup-test-database"` // 清理残余的测试数据库(程序异常退出或未开启drop-test-temporary) issue #48
OnlySyntaxCheck bool `yaml:"only-syntax-check"` // 只做语法检查不输出优化建议
SamplingStatisticTarget int `yaml:"sampling-statistic-target"` // 数据采样因子,对应 PostgreSQL 的 default_statistics_target
Sampling bool `yaml:"sampling"` // 数据采样开关
SamplingCondition string `yaml:"sampling-condition"` // 指定采样条件,如:WHERE xxx LIMIT xxx;
Profiling bool `yaml:"profiling"` // 在开启数据采样的情况下,在测试环境执行进行profile
Trace bool `yaml:"trace"` // 在开启数据采样的情况下,在测试环境执行进行Trace
Explain bool `yaml:"explain"` // Explain开关
Delimiter string `yaml:"delimiter"` // SQL分隔符
// +++++++++++++++日志相关+++++++++++++++++
// 日志级别,这里使用了 beego 的 log 包
// [0:Emergency, 1:Alert, 2:Critical, 3:Error, 4:Warning, 5:Notice, 6:Informational, 7:Debug]
LogLevel int `yaml:"log-level"`
// 日志输出位置,默认日志输出到控制台
// 目前只支持['console', 'file']两种形式,如非console形式这里需要指定文件的路径,可以是相对路径
LogOutput string `yaml:"log-output"`
// 优化建议输出格式,目前支持: json, text, markdown格式,如指定其他格式会给 pretty.Println 的输出
ReportType string `yaml:"report-type"`
// 当 ReportType 为 html 格式时使用的 css 风格,如不指定会提供一个默认风格。CSS可 以是本地文件,也可以是一个URL
ReportCSS string `yaml:"report-css"`
// 当 ReportType 为 html 格式时使用的 javascript 脚本,如不指定默认会加载SQL pretty 使用的 javascript。像CSS一样可以是本地文件,也可以是一个URL
ReportJavascript string `yaml:"report-javascript"`
// 当ReportType 为 html 格式时,HTML 的 title
ReportTitle string `yaml:"report-title"`
// blackfriday markdown2html config
MarkdownExtensions int `yaml:"markdown-extensions"` // markdown 转 html 支持的扩展包, 参考blackfriday
MarkdownHTMLFlags int `yaml:"markdown-html-flags"` // markdown 转 html 支持的 flag, 参考blackfriday, default 0
// ++++++++++++++优化建议相关++++++++++++++
IgnoreRules []string `yaml:"ignore-rules"` // 忽略的优化建议规则
RewriteRules []string `yaml:"rewrite-rules"` // 生效的重写规则
BlackList string `yaml:"blacklist"` // blacklist 中的 SQL 不会被评审,可以是指纹,也可以是正则
MaxJoinTableCount int `yaml:"max-join-table-count"` // 单条 SQL 中 JOIN 表的最大数量
MaxGroupByColsCount int `yaml:"max-group-by-cols-count"` // 单条 SQL 中 GroupBy 包含列的最大数量
MaxDistinctCount int `yaml:"max-distinct-count"` // 单条 SQL 中 Distinct 的最大数量
MaxIdxColsCount int `yaml:"max-index-cols-count"` // 复合索引中包含列的最大数量
MaxTextColsCount int `yaml:"max-text-cols-count"` // 表中含有的 text/blob 列的最大数量
MaxTotalRows uint64 `yaml:"max-total-rows"` // 计算散粒度时,当数据行数大于 MaxTotalRows 即开启数据库保护模式,散粒度返回结果可信度下降
MaxQueryCost int64 `yaml:"max-query-cost"` // last_query_cost 超过该值时将给予警告
SpaghettiQueryLength int `yaml:"spaghetti-query-length"` // SQL最大长度警告,超过该长度会给警告
AllowDropIndex bool `yaml:"allow-drop-index"` // 允许输出删除重复索引的建议
MaxInCount int `yaml:"max-in-count"` // IN()最大数量
MaxIdxBytesPerColumn int `yaml:"max-index-bytes-percolumn"` // 索引中单列最大字节数,默认767
MaxIdxBytes int `yaml:"max-index-bytes"` // 索引总长度限制,默认3072
AllowCharsets []string `yaml:"allow-charsets"` // 允许使用的 DEFAULT CHARSET
AllowCollates []string `yaml:"allow-collates"` // 允许使用的 COLLATE
AllowEngines []string `yaml:"allow-engines"` // 允许使用的存储引擎
MaxIdxCount int `yaml:"max-index-count"` // 单张表允许最多索引数
MaxColCount int `yaml:"max-column-count"` // 单张表允许最大列数
MaxValueCount int `yaml:"max-value-count"` // INSERT/REPLACE 单次允许批量写入的行数
IdxPrefix string `yaml:"index-prefix"` // 普通索引建议使用的前缀
UkPrefix string `yaml:"unique-key-prefix"` // 唯一键建议使用的前缀
MaxSubqueryDepth int `yaml:"max-subquery-depth"` // 子查询最大尝试
MaxVarcharLength int `yaml:"max-varchar-length"` // varchar最大长度
ColumnNotAllowType []string `yaml:"column-not-allow-type"` // 字段不允许使用的数据类型
MinCardinality float64 `yaml:"min-cardinality"` // 添加索引散粒度阈值,范围 0~100
// ++++++++++++++EXPLAIN检查项+++++++++++++
ExplainSQLReportType string `yaml:"explain-sql-report-type"` // EXPLAIN markdown 格式输出 SQL 样式,支持 sample, fingerprint, pretty 等
ExplainType string `yaml:"explain-type"` // EXPLAIN方式 [traditional, extended, partitions]
ExplainFormat string `yaml:"explain-format"` // FORMAT=[json, traditional]
ExplainWarnSelectType []string `yaml:"explain-warn-select-type"` // 哪些 select_type 不建议使用
ExplainWarnAccessType []string `yaml:"explain-warn-access-type"` // 哪些 access type 不建议使用
ExplainMaxKeyLength int `yaml:"explain-max-keys"` // 最大 key_len
ExplainMinPossibleKeys int `yaml:"explain-min-keys"` // 最小 possible_keys 警告
ExplainMaxRows int64 `yaml:"explain-max-rows"` // 最大扫描行数警告
ExplainWarnExtra []string `yaml:"explain-warn-extra"` // 哪些 extra 信息会给警告
ExplainMaxFiltered float64 `yaml:"explain-max-filtered"` // filtered 大于该配置给出警告
ExplainWarnScalability []string `yaml:"explain-warn-scalability"` // 复杂度警告名单
ShowWarnings bool `yaml:"show-warnings"` // explain extended with show warnings
ShowLastQueryCost bool `yaml:"show-last-query-cost"` // switch with show status like 'last_query_cost'
// ++++++++++++++其他配置项+++++++++++++++
Query string `yaml:"query"` // 需要进行调优的SQL
ListHeuristicRules bool `yaml:"list-heuristic-rules"` // 打印支持的评审规则列表
ListRewriteRules bool `yaml:"list-rewrite-rules"` // 打印重写规则
ListTestSqls bool `yaml:"list-test-sqls"` // 打印测试case用于测试
ListReportTypes bool `yaml:"list-report-types"` // 打印支持的报告输出类型
Verbose bool `yaml:"verbose"` // verbose模式,会多输出一些信息
DryRun bool `yaml:"dry-run"` // 是否在预演环境执行
MaxPrettySQLLength int `yaml:"max-pretty-sql-length"` // 超出该长度的SQL会转换成指纹输出
}
Configuration 配置文件定义结构体
type Dsn ¶
type Dsn struct {
User string `yaml:"user"` // Usernames
Password string `yaml:"password"` // Password (requires User)
Net string `yaml:"net"` // Network type
Addr string `yaml:"addr"` // Network address (requires Net)
Schema string `yaml:"schema"` // Database name
Charset string `yaml:"charset"` // SET NAMES charset
Collation string `yaml:"collation"` // Connection collation
Loc string `yaml:"loc"` // Location for time.Time values
TLS string `yaml:"tls"` // TLS configuration name
ServerPubKey string `yaml:"server-public-key"` // Server public key name
MaxAllowedPacket int `yaml:"max-allowed-packet"` // Max packet size allowed
Params map[string]string `yaml:"params"` // Other Connection parameters, `SET param=val`, `SET NAMES charset`
Timeout string `yaml:"timeout"` // Dial timeout
ReadTimeout string `yaml:"read-timeout"` // I/O read timeout
WriteTimeout string `yaml:"write-timeout"` // I/O write timeout
AllowNativePasswords bool `yaml:"allow-native-passwords"` // Allows the native password authentication method
AllowOldPasswords bool `yaml:"allow-old-passwords"` // Allows the old insecure password method
Disable bool `yaml:"disable"`
Version int `yaml:"-"` // 版本自动检查,不可配置
}
Dsn Data source name
type ReportType ¶
type ReportType struct {
Name string `json:"Name"`
Description string `json:"Description"`
Example string `json:"Example"`
}
ReportType 元数据结构定义
type TableColumns ¶
TableColumns 这个结构体中的元素是有序的 map[db]map[table][]columns