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