提交 49a306c6 编写于 作者: martianzhang's avatar martianzhang

fix #47, #37

  #47 pretty print function `format` endless loop
  #37 -report-type not in (markdown, html) will not print score
上级 b80ed7fe
...@@ -1098,8 +1098,8 @@ func InBlackList(sql string) bool { ...@@ -1098,8 +1098,8 @@ func InBlackList(sql string) bool {
} }
// FormatSuggest 格式化输出优化建议 // FormatSuggest 格式化输出优化建议
// 目前支持:json, text两种形式,其他形式会给结构体的pretty.Println
func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[string]Rule, string) { func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[string]Rule, string) {
common.Log.Debug("FormatSuggest, Query: %s", sql)
var fingerprint, id string var fingerprint, id string
var buf []string var buf []string
var score = 100 var score = 100
...@@ -1145,7 +1145,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1145,7 +1145,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
delete(suggest, k) delete(suggest, k)
} }
} }
common.Log.Debug("FormatSuggest, format: %s", format)
switch format { switch format {
case "json": case "json":
js, err := json.MarshalIndent(Result{ js, err := json.MarshalIndent(Result{
...@@ -1192,6 +1192,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1192,6 +1192,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
} }
// MySQL // MySQL
common.Log.Debug("FormatSuggest, start of sortedMySQLSuggest")
var sortedMySQLSuggest []string var sortedMySQLSuggest []string
for item := range suggest { for item := range suggest {
if strings.HasPrefix(item, "ERR") { if strings.HasPrefix(item, "ERR") {
...@@ -1213,6 +1214,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1213,6 +1214,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
// Explain // Explain
common.Log.Debug("FormatSuggest, start of sortedExplainSuggest")
if suggest["EXP.000"].Item != "" { if suggest["EXP.000"].Item != "" {
buf = append(buf, fmt.Sprintln("## ", suggest["EXP.000"].Summary)) buf = append(buf, fmt.Sprintln("## ", suggest["EXP.000"].Summary))
buf = append(buf, fmt.Sprintln(suggest["EXP.000"].Content)) buf = append(buf, fmt.Sprintln(suggest["EXP.000"].Content))
...@@ -1233,6 +1235,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1233,6 +1235,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
// Profiling // Profiling
common.Log.Debug("FormatSuggest, start of sortedProfilingSuggest")
var sortedProfilingSuggest []string var sortedProfilingSuggest []string
for item := range suggest { for item := range suggest {
if strings.HasPrefix(item, "PRO") { if strings.HasPrefix(item, "PRO") {
...@@ -1249,6 +1252,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1249,6 +1252,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
// Trace // Trace
common.Log.Debug("FormatSuggest, start of sortedTraceSuggest")
var sortedTraceSuggest []string var sortedTraceSuggest []string
for item := range suggest { for item := range suggest {
if strings.HasPrefix(item, "TRA") { if strings.HasPrefix(item, "TRA") {
...@@ -1265,6 +1269,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1265,6 +1269,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
// Index // Index
common.Log.Debug("FormatSuggest, start of sortedIdxSuggest")
var sortedIdxSuggest []string var sortedIdxSuggest []string
for item := range suggest { for item := range suggest {
if strings.HasPrefix(item, "IDX") { if strings.HasPrefix(item, "IDX") {
...@@ -1293,6 +1298,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1293,6 +1298,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
// Heuristic // Heuristic
common.Log.Debug("FormatSuggest, start of sortedHeuristicSuggest")
var sortedHeuristicSuggest []string var sortedHeuristicSuggest []string
for item := range suggest { for item := range suggest {
if !strings.HasPrefix(item, "EXP") && if !strings.HasPrefix(item, "EXP") &&
...@@ -1321,6 +1327,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1321,6 +1327,7 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
} }
default: default:
common.Log.Debug("unknown report-type %s", format)
buf = append(buf, fmt.Sprintln("Query: ", sql)) buf = append(buf, fmt.Sprintln("Query: ", sql))
for _, rule := range suggest { for _, rule := range suggest {
buf = append(buf, pretty.Sprint(rule)) buf = append(buf, pretty.Sprint(rule))
...@@ -1330,12 +1337,12 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[ ...@@ -1330,12 +1337,12 @@ func FormatSuggest(sql string, format string, suggests ...map[string]Rule) (map[
// 打分 // 打分
var str string var str string
switch common.Config.ReportType { switch common.Config.ReportType {
case "explain-digest", "lint": case "markdown", "html":
str = strings.Join(buf, "\n")
default:
if len(buf) > 1 { if len(buf) > 1 {
str = buf[0] + "\n" + common.Score(score) + "\n\n" + strings.Join(buf[1:], "\n") str = buf[0] + "\n" + common.Score(score) + "\n\n" + strings.Join(buf[1:], "\n")
} }
default:
str = strings.Join(buf, "\n")
} }
return suggest, str return suggest, str
......
create table hello.t (id int unsigned);
SELECT * FROM film WHERE length = 86; SELECT * FROM film WHERE length = 86;
SELECT * FROM film WHERE length IS NULL; SELECT * FROM film WHERE length IS NULL;
SELECT * FROM film HAVING title = 'abc'; SELECT * FROM film HAVING title = 'abc';
...@@ -80,3 +79,5 @@ SELECT description FROM film WHERE description IN('NEWS','asd') GROUP BY descrip ...@@ -80,3 +79,5 @@ SELECT description FROM film WHERE description IN('NEWS','asd') GROUP BY descrip
alter table address add index idx_city_id(city_id); alter table address add index idx_city_id(city_id);
alter table inventory add index `idx_store_film` (`store_id`,`film_id`); alter table inventory add index `idx_store_film` (`store_id`,`film_id`);
alter table inventory add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`); alter table inventory add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`);
SELECT DATE_FORMAT(t.atm, '%Y-%m-%d'), COUNT(DISTINCT (t.usr)) FROM usr_terminal t WHERE t.atm > '2018-10-22 00:00:00' AND t.agent LIKE '%Chrome%' AND t.system = 'eip' GROUP BY DATE_FORMAT(t.atm, '%Y-%m-%d') ORDER BY DATE_FORMAT(t.atm, '%Y-%m-%d')
create table hello.t (id int unsigned);
...@@ -28,6 +28,7 @@ import ( ...@@ -28,6 +28,7 @@ import (
// Pretty 格式化输出SQL // Pretty 格式化输出SQL
func Pretty(sql string, method string) (output string) { func Pretty(sql string, method string) (output string) {
common.Log.Debug("Pretty, Query: %s, method: %s", sql, method)
// 超出 Config.MaxPrettySQLLength 长度的SQL会对其指纹进行pretty // 超出 Config.MaxPrettySQLLength 长度的SQL会对其指纹进行pretty
if len(sql) > common.Config.MaxPrettySQLLength { if len(sql) > common.Config.MaxPrettySQLLength {
fingerprint := query.Fingerprint(sql) fingerprint := query.Fingerprint(sql)
...@@ -216,6 +217,8 @@ func format(query string) string { ...@@ -216,6 +217,8 @@ func format(query string) string {
if j.Value.(string) == "special" { if j.Value.(string) == "special" {
if indentLevel > 0 { if indentLevel > 0 {
indentLevel-- indentLevel--
} else {
break
} }
} else { } else {
break break
......
SELECT * FROM film WHERE length = 86;
SELECT
*
FROM
film
WHERE
LENGTH = 86;
SELECT * FROM film WHERE length IS NULL;
SELECT
*
FROM
film
WHERE
LENGTH IS NULL;
SELECT * FROM film HAVING title = 'abc';
SELECT
*
FROM
film
HAVING
title = 'abc';
SELECT * FROM sakila.film WHERE length >= 60;
SELECT
*
FROM
sakila. film
WHERE
LENGTH >= 60;
SELECT * FROM sakila.film WHERE length >= '60';
SELECT
*
FROM
sakila. film
WHERE
LENGTH >= '60';
SELECT * FROM film WHERE length BETWEEN 60 AND 84;
SELECT
*
FROM
film
WHERE
LENGTH BETWEEN 60
AND 84;
SELECT * FROM film WHERE title LIKE 'AIR%';
SELECT
*
FROM
film
WHERE
title LIKE 'AIR%';
SELECT * FROM film WHERE title IS NOT NULL;
SELECT
*
FROM
film
WHERE
title IS NOT NULL;
SELECT * FROM film WHERE length = 114 and title = 'ALABAMA DEVIL';
SELECT
*
FROM
film
WHERE
LENGTH = 114
AND title = 'ALABAMA DEVIL';
SELECT * FROM film WHERE length > 100 and title = 'ALABAMA DEVIL';
SELECT
*
FROM
film
WHERE
LENGTH > 100
AND title = 'ALABAMA DEVIL';
SELECT * FROM film WHERE length > 100 and language_id < 10 and title = 'xyz';
SELECT
*
FROM
film
WHERE
LENGTH > 100
AND language_id < 10
AND title = 'xyz';
SELECT * FROM film WHERE length > 100 and language_id < 10;
SELECT
*
FROM
film
WHERE
LENGTH > 100
AND language_id < 10;
SELECT release_year, sum(length) FROM film WHERE length = 123 AND language_id = 1 GROUP BY release_year;
SELECT
release_year, SUM( LENGTH)
FROM
film
WHERE
LENGTH = 123
AND language_id = 1
GROUP BY
release_year;
SELECT release_year, sum(length) FROM film WHERE length >= 123 GROUP BY release_year;
SELECT
release_year, SUM( LENGTH)
FROM
film
WHERE
LENGTH >= 123
GROUP BY
release_year;
SELECT release_year, language_id, sum(length) FROM film GROUP BY release_year, language_id;
SELECT
release_year, language_id, SUM( LENGTH)
FROM
film
GROUP BY
release_year, language_id;
SELECT release_year, sum(length) FROM film WHERE length = 123 GROUP BY release_year,(length+language_id);
SELECT
release_year, SUM( LENGTH)
FROM
film
WHERE
LENGTH = 123
GROUP BY
release_year, (LENGTH+ language_id);
SELECT release_year, sum(film_id) FROM film GROUP BY release_year;
SELECT
release_year, SUM( film_id)
FROM
film
GROUP BY
release_year;
SELECT * FROM address GROUP BY address,district;
SELECT
*
FROM
address
GROUP BY
address, district;
SELECT title FROM film WHERE ABS(language_id) = 3 GROUP BY title;
SELECT
title
FROM
film
WHERE
ABS( language_id) = 3
GROUP BY
title;
SELECT language_id FROM film WHERE length = 123 GROUP BY release_year ORDER BY language_id;
SELECT
language_id
FROM
film
WHERE
LENGTH = 123
GROUP BY
release_year
ORDER BY
language_id;
SELECT release_year FROM film WHERE length = 123 GROUP BY release_year ORDER BY release_year;
SELECT
release_year
FROM
film
WHERE
LENGTH = 123
GROUP BY
release_year
ORDER BY
release_year;
SELECT * FROM film WHERE length = 123 ORDER BY release_year ASC, language_id DESC;
SELECT
*
FROM
film
WHERE
LENGTH = 123
ORDER BY
release_year ASC, language_id DESC;
SELECT release_year FROM film WHERE length = 123 GROUP BY release_year ORDER BY release_year LIMIT 10;
SELECT
release_year
FROM
film
WHERE
LENGTH = 123
GROUP BY
release_year
ORDER BY
release_year
LIMIT
10;
SELECT * FROM film WHERE length = 123 ORDER BY release_year LIMIT 10;
SELECT
*
FROM
film
WHERE
LENGTH = 123
ORDER BY
release_year
LIMIT
10;
SELECT * FROM film ORDER BY release_year LIMIT 10;
SELECT
*
FROM
film
ORDER BY
release_year
LIMIT
10;
SELECT film_id FROM film ORDER BY release_year LIMIT 10;
SELECT
film_id
FROM
film
ORDER BY
release_year
LIMIT
10;
SELECT * FROM film WHERE length > 100 ORDER BY length LIMIT 10;
SELECT
*
FROM
film
WHERE
LENGTH > 100
ORDER BY
LENGTH
LIMIT
10;
SELECT * FROM film WHERE length < 100 ORDER BY length LIMIT 10;
SELECT
*
FROM
film
WHERE
LENGTH < 100
ORDER BY
LENGTH
LIMIT
10;
SELECT * FROM customer WHERE address_id in (224,510) ORDER BY last_name;
SELECT
*
FROM
customer
WHERE
address_id in (224, 510)
ORDER BY
last_name;
SELECT * FROM film WHERE release_year = 2016 AND length != 1 ORDER BY title;
SELECT
*
FROM
film
WHERE
release_year = 2016
AND LENGTH != 1
ORDER BY
title;
SELECT title FROM film WHERE release_year = 1995;
SELECT
title
FROM
film
WHERE
release_year = 1995;
SELECT title, replacement_cost FROM film WHERE language_id = 5 AND length = 70;
SELECT
title, replacement_cost
FROM
film
WHERE
language_id = 5
AND LENGTH = 70;
SELECT title FROM film WHERE language_id > 5 AND length > 70;
SELECT
title
FROM
film
WHERE
language_id > 5
AND LENGTH > 70;
SELECT * FROM film WHERE length = 100 and title = 'xyz' ORDER BY release_year;
SELECT
*
FROM
film
WHERE
LENGTH = 100
AND title = 'xyz'
ORDER BY
release_year;
SELECT * FROM film WHERE length > 100 and title = 'xyz' ORDER BY release_year;
SELECT
*
FROM
film
WHERE
LENGTH > 100
AND title = 'xyz'
ORDER BY
release_year;
SELECT * FROM film WHERE length > 100 ORDER BY release_year;
SELECT
*
FROM
film
WHERE
LENGTH > 100
ORDER BY
release_year;
SELECT * FROM city a INNER JOIN country b ON a.country_id=b.country_id;
SELECT
*
FROM
city a
INNER JOIN country b ON a. country_id= b. country_id;
SELECT * FROM city a LEFT JOIN country b ON a.country_id=b.country_id;
SELECT
*
FROM
city a
LEFT JOIN country b ON a. country_id= b. country_id;
SELECT * FROM city a RIGHT JOIN country b ON a.country_id=b.country_id;
SELECT
*
FROM
city a
RIGHT JOIN country b ON a. country_id= b. country_id;
SELECT * FROM city a LEFT JOIN country b ON a.country_id=b.country_id WHERE b.last_update IS NULL;
SELECT
*
FROM
city a
LEFT JOIN country b ON a. country_id= b. country_id
WHERE
b. last_update IS NULL;
SELECT * FROM city a RIGHT JOIN country b ON a.country_id=b.country_id WHERE a.last_update IS NULL;
SELECT
*
FROM
city a
RIGHT JOIN country b ON a. country_id= b. country_id
WHERE
a. last_update IS NULL;
SELECT * FROM city a LEFT JOIN country b ON a.country_id=b.country_id UNION SELECT * FROM city a RIGHT JOIN country b ON a.country_id=b.country_id;
SELECT
*
FROM
city a
LEFT JOIN country b ON a. country_id= b. country_id
UNION
SELECT
*
FROM
city a
RIGHT JOIN country b ON a. country_id= b. country_id;
SELECT * FROM city a RIGHT JOIN country b ON a.country_id=b.country_id WHERE a.last_update IS NULL UNION SELECT * FROM city a LEFT JOIN country b ON a.country_id=b.country_id WHERE b.last_update IS NULL;
SELECT
*
FROM
city a
RIGHT JOIN country b ON a. country_id= b. country_id
WHERE
a. last_update IS NULL
UNION
SELECT
*
FROM
city a
LEFT JOIN country b ON a. country_id= b. country_id
WHERE
b. last_update IS NULL;
SELECT country_id, last_update FROM city NATURAL JOIN country;
SELECT
country_id, last_update
FROM
city NATURAL
JOIN country;
SELECT country_id, last_update FROM city NATURAL LEFT JOIN country;
SELECT
country_id, last_update
FROM
city NATURAL
LEFT JOIN country;
SELECT country_id, last_update FROM city NATURAL RIGHT JOIN country;
SELECT
country_id, last_update
FROM
city NATURAL
RIGHT JOIN country;
SELECT a.country_id, a.last_update FROM city a STRAIGHT_JOIN country b ON a.country_id=b.country_id;
SELECT
a. country_id, a. last_update
FROM
city a STRAIGHT_JOIN country b ON a. country_id= b. country_id;
SELECT d.deptno,d.dname,d.loc FROM scott.dept d WHERE d.deptno IN (SELECT e.deptno FROM scott.emp e);
SELECT
d. deptno, d. dname, d. loc
FROM
scott. dept d
WHERE
d. deptno IN (
SELECT
e. deptno
FROM
scott. emp e);
SELECT visitor_id, url FROM (SELECT id FROM log WHERE ip="123.45.67.89" order by tsdesc limit 50, 10) I JOIN log ON (I.id=log.id) JOIN url ON (url.id=log.url_id) order by TS desc;
SELECT
visitor_id, url
FROM
(
SELECT
id
FROM
LOG
WHERE
ip= "123.45.67.89"
ORDER BY
tsdesc
LIMIT
50, 10) I
JOIN LOG ON (I. id= LOG. id)
JOIN url ON (url. id= LOG. url_id)
ORDER BY
TS desc;
DELETE city, country FROM city INNER JOIN country using (country_id) WHERE city.city_id = 1;
DELETE city, country
FROM
city
INNER JOIN country using (country_id)
WHERE
city. city_id = 1;
DELETE city FROM city LEFT JOIN country ON city.country_id = country.country_id WHERE country.country IS NULL;
DELETE city
FROM
city
LEFT JOIN country ON city. country_id = country. country_id
WHERE
country. country IS NULL;
DELETE a1, a2 FROM city AS a1 INNER JOIN country AS a2 WHERE a1.country_id=a2.country_id;
DELETE a1, a2
FROM
city AS a1
INNER JOIN country AS a2
WHERE
a1. country_id= a2. country_id;
DELETE FROM a1, a2 USING city AS a1 INNER JOIN country AS a2 WHERE a1.country_id=a2.country_id;
DELETE FROM
a1, a2 USING city AS a1
INNER JOIN country AS a2
WHERE
a1. country_id= a2. country_id;
DELETE FROM film WHERE length > 100;
DELETE FROM
film
WHERE
LENGTH > 100;
UPDATE city INNER JOIN country USING(country_id) SET city.city = 'Abha', city.last_update = '2006-02-15 04:45:25', country.country = 'Afghanistan' WHERE city.city_id=10;
UPDATE
city
INNER JOIN country USING( country_id)
SET
city. city = 'Abha',
city. last_update = '2006-02-15 04:45:25',
country. country = 'Afghanistan'
WHERE
city. city_id= 10;
UPDATE city INNER JOIN country ON city.country_id = country.country_id INNER JOIN address ON city.city_id = address.city_id SET city.city = 'Abha', city.last_update = '2006-02-15 04:45:25', country.country = 'Afghanistan' WHERE city.city_id=10;
UPDATE
city
INNER JOIN country ON city. country_id = country. country_id
INNER JOIN address ON city. city_id = address. city_id
SET
city. city = 'Abha',
city. last_update = '2006-02-15 04:45:25',
country. country = 'Afghanistan'
WHERE
city. city_id= 10;
UPDATE city, country SET city.city = 'Abha', city.last_update = '2006-02-15 04:45:25', country.country = 'Afghanistan' WHERE city.country_id = country.country_id AND city.city_id=10;
UPDATE
city, country
SET
city. city = 'Abha',
city. last_update = '2006-02-15 04:45:25',
country. country = 'Afghanistan'
WHERE
city. country_id = country. country_id
AND city. city_id= 10;
UPDATE film SET length = 10 WHERE language_id = 20;
UPDATE
film
SET
LENGTH = 10
WHERE
language_id = 20;
INSERT INTO city (country_id) SELECT country_id FROM country;
INSERT INTO city (country_id)
SELECT
country_id
FROM
country;
INSERT INTO city (country_id) VALUES (1),(2),(3);
INSERT INTO city (country_id)
VALUES
(1),
(2),
(3);
INSERT INTO city (country_id) VALUES (10);
INSERT INTO city (country_id)
VALUES
(10);
INSERT INTO city (country_id) SELECT 10 FROM DUAL;
INSERT INTO city (country_id)
SELECT
10
FROM
DUAL;
REPLACE INTO city (country_id) SELECT country_id FROM country;
REPLACE INTO city (country_id)
SELECT
country_id
FROM
country;
REPLACE INTO city (country_id) VALUES (1),(2),(3);
REPLACE INTO city (country_id)
VALUES
(1),
(2),
(3);
REPLACE INTO city (country_id) VALUES (10);
REPLACE INTO city (country_id)
VALUES
(10);
REPLACE INTO city (country_id) SELECT 10 FROM DUAL;
REPLACE INTO city (country_id)
SELECT
10
FROM
DUAL;
SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM ( SELECT film_id FROM film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film ) film;
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
(
SELECT
film_id
FROM
film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film
) film;
SELECT * FROM film WHERE language_id = (SELECT language_id FROM language LIMIT 1);
SELECT
*
FROM
film
WHERE
language_id = (
SELECT
language_id
FROM
language
LIMIT
1);
SELECT * FROM city i left JOIN country o ON i.city_id=o.country_id union SELECT * FROM city i right JOIN country o ON i.city_id=o.country_id;
SELECT
*
FROM
city i
LEFT JOIN country o ON i. city_id= o. country_id
UNION
SELECT
*
FROM
city i
RIGHT JOIN country o ON i. city_id= o. country_id;
SELECT * FROM (SELECT * FROM actor WHERE last_update='2006-02-15 04:34:33' and last_name='CHASE') t WHERE last_update='2006-02-15 04:34:33' and last_name='CHASE' GROUP BY first_name;
SELECT
*
FROM
(
SELECT
*
FROM
actor
WHERE
last_update= '2006-02-15 04:34:33'
AND last_name= 'CHASE'
) t
WHERE
last_update= '2006-02-15 04:34:33'
AND last_name= 'CHASE'
GROUP BY
first_name;
SELECT * FROM city i left JOIN country o ON i.city_id=o.country_id union SELECT * FROM city i right JOIN country o ON i.city_id=o.country_id;
SELECT
*
FROM
city i
LEFT JOIN country o ON i. city_id= o. country_id
UNION
SELECT
*
FROM
city i
RIGHT JOIN country o ON i. city_id= o. country_id;
SELECT * FROM city i left JOIN country o ON i.city_id=o.country_id WHERE o.country_id is null union SELECT * FROM city i right JOIN country o ON i.city_id=o.country_id WHERE i.city_id is null;
SELECT
*
FROM
city i
LEFT JOIN country o ON i. city_id= o. country_id
WHERE
o. country_id is null
UNION
SELECT
*
FROM
city i
RIGHT JOIN country o ON i. city_id= o. country_id
WHERE
i. city_id is null;
SELECT first_name,last_name,email FROM customer STRAIGHT_JOIN address ON customer.address_id=address.address_id;
SELECT
first_name, last_name, email
FROM
customer STRAIGHT_JOIN address ON customer. address_id= address. address_id;
SELECT ID,name FROM (SELECT address FROM customer_list WHERE SID=1 order by phone limit 50,10) a JOIN customer_list l ON (a.address=l.address) JOIN city c ON (c.city=l.city) order by phone desc;
SELECT
ID, name
FROM
(
SELECT
address
FROM
customer_list
WHERE
SID= 1
ORDER BY
phone
LIMIT
50, 10) a
JOIN customer_list l ON (a. address= l. address)
JOIN city c ON (c. city= l. city)
ORDER BY
phone desc;
SELECT * FROM film WHERE date(last_update)='2006-02-15';
SELECT
*
FROM
film
WHERE
DATE( last_update) = '2006-02-15';
SELECT last_update FROM film GROUP BY date(last_update);
SELECT
last_update
FROM
film
GROUP BY
DATE( last_update);
SELECT last_update FROM film order by date(last_update);
SELECT
last_update
FROM
film
ORDER BY
DATE( last_update);
SELECT description FROM film WHERE description IN('NEWS','asd') GROUP BY description;
SELECT
description
FROM
film
WHERE
description IN( 'NEWS',
'asd'
)
GROUP BY
description;
alter table address add index idx_city_id(city_id);
ALTER TABLE
address
ADD
index idx_city_id( city_id);
alter table inventory add index `idx_store_film` (`store_id`,`film_id`);
ALTER TABLE
inventory
ADD
index `idx_store_film` (
`store_id`, `film_id`);
alter table inventory add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`);
ALTER TABLE
inventory
ADD
index `idx_store_film` (
`store_id`, `film_id`),
ADD
index `idx_store_film` (
`store_id`, `film_id`),
ADD
index `idx_store_film` (
`store_id`, `film_id`);
SELECT DATE_FORMAT(t.atm, '%Y-%m-%d'), COUNT(DISTINCT (t.usr)) FROM usr_terminal t WHERE t.atm > '2018-10-22 00:00:00' AND t.agent LIKE '%Chrome%' AND t.system = 'eip' GROUP BY DATE_FORMAT(t.atm, '%Y-%m-%d') ORDER BY DATE_FORMAT(t.atm, '%Y-%m-%d')
SELECT
DATE_FORMAT( t. atm, '%Y-%m-%d'
),
COUNT( DISTINCT (
t. usr))
FROM
usr_terminal t
WHERE
t. atm > '2018-10-22 00:00:00'
AND t. agent LIKE '%Chrome%'
AND t. system = 'eip'
GROUP BY
DATE_FORMAT( t. atm, '%Y-%m-%d'
)
ORDER BY
DATE_FORMAT( t. atm, '%Y-%m-%d'
)
create table hello.t (id int unsigned);
create table hello. t (id int unsigned);
...@@ -630,8 +630,6 @@ ALTER TABLE t1 CHANGE b a INT NOT NULL; ...@@ -630,8 +630,6 @@ ALTER TABLE t1 CHANGE b a INT NOT NULL;
ALTER TABLE ALTER TABLE
t1 CHANGE b a INT NOT NULL; t1 CHANGE b a INT NOT NULL;
create table hello.t (id int unsigned);
create table hello. t (id int unsigned);
SELECT * FROM film WHERE length = 86; SELECT * FROM film WHERE length = 86;
SELECT SELECT
...@@ -1480,3 +1478,24 @@ ADD ...@@ -1480,3 +1478,24 @@ ADD
ADD ADD
index `idx_store_film` ( index `idx_store_film` (
`store_id`, `film_id`); `store_id`, `film_id`);
SELECT DATE_FORMAT(t.atm, '%Y-%m-%d'), COUNT(DISTINCT (t.usr)) FROM usr_terminal t WHERE t.atm > '2018-10-22 00:00:00' AND t.agent LIKE '%Chrome%' AND t.system = 'eip' GROUP BY DATE_FORMAT(t.atm, '%Y-%m-%d') ORDER BY DATE_FORMAT(t.atm, '%Y-%m-%d')
SELECT
DATE_FORMAT( t. atm, '%Y-%m-%d'
),
COUNT( DISTINCT (
t. usr))
FROM
usr_terminal t
WHERE
t. atm > '2018-10-22 00:00:00'
AND t. agent LIKE '%Chrome%'
AND t. system = 'eip'
GROUP BY
DATE_FORMAT( t. atm, '%Y-%m-%d'
)
ORDER BY
DATE_FORMAT( t. atm, '%Y-%m-%d'
)
create table hello.t (id int unsigned);
create table hello. t (id int unsigned);
...@@ -77,9 +77,14 @@ func TestCompress(t *testing.T) { ...@@ -77,9 +77,14 @@ func TestCompress(t *testing.T) {
} }
func TestFormat(t *testing.T) { func TestFormat(t *testing.T) {
for _, sql := range common.TestSQLs { err := common.GoldenDiff(func() {
fmt.Println(sql) for _, sql := range common.TestSQLs {
fmt.Println(format(sql)) fmt.Println(sql)
fmt.Println(format(sql))
}
}, t.Name(), update)
if nil != err {
t.Fatal(err)
} }
} }
......
...@@ -257,6 +257,7 @@ func main() { ...@@ -257,6 +257,7 @@ func main() {
// +++++++++++++++++++++语法检查[结束]+++++++++++++++++++++++} // +++++++++++++++++++++语法检查[结束]+++++++++++++++++++++++}
// +++++++++++++++++++++启发式规则建议[开始]+++++++++++++++++++++++{ // +++++++++++++++++++++启发式规则建议[开始]+++++++++++++++++++++++{
common.Log.Debug("start of heuristic advisor Query: %s", q.Query)
for item, rule := range advisor.HeuristicRules { for item, rule := range advisor.HeuristicRules {
// 去除忽略的建议检查 // 去除忽略的建议检查
okFunc := (*advisor.Query4Audit).RuleOK okFunc := (*advisor.Query4Audit).RuleOK
...@@ -267,11 +268,13 @@ func main() { ...@@ -267,11 +268,13 @@ func main() {
} }
} }
} }
common.Log.Debug("end of heuristic advisor Query: %s", q.Query)
// +++++++++++++++++++++启发式规则建议[结束]+++++++++++++++++++++++} // +++++++++++++++++++++启发式规则建议[结束]+++++++++++++++++++++++}
// +++++++++++++++++++++索引优化建议[开始]+++++++++++++++++++++++{ // +++++++++++++++++++++索引优化建议[开始]+++++++++++++++++++++++{
// 如果配置了索引建议过滤规则,不进行索引优化建议 // 如果配置了索引建议过滤规则,不进行索引优化建议
// 在配置文件ignore-rules中添加 'IDX.*'即可屏蔽索引优化建议 // 在配置文件ignore-rules中添加 'IDX.*'即可屏蔽索引优化建议
common.Log.Debug("start of index advisor Query: %s", q.Query)
if !advisor.IsIgnoreRule("IDX.") { if !advisor.IsIgnoreRule("IDX.") {
if vEnv.BuildVirtualEnv(rEnv, q.Query) { if vEnv.BuildVirtualEnv(rEnv, q.Query) {
idxAdvisor, err := advisor.NewAdvisor(vEnv, *rEnv, *q) idxAdvisor, err := advisor.NewAdvisor(vEnv, *rEnv, *q)
...@@ -314,10 +317,12 @@ func main() { ...@@ -314,10 +317,12 @@ func main() {
common.Log.Error("vEnv.BuildVirtualEnv Error: prepare SQL '%s' in vEnv failed.", q.Query) common.Log.Error("vEnv.BuildVirtualEnv Error: prepare SQL '%s' in vEnv failed.", q.Query)
} }
} }
common.Log.Debug("end of index advisor Query: %s", q.Query)
// +++++++++++++++++++++索引优化建议[结束]+++++++++++++++++++++++} // +++++++++++++++++++++索引优化建议[结束]+++++++++++++++++++++++}
// +++++++++++++++++++++EXPLAIN建议[开始]+++++++++++++++++++++++{ // +++++++++++++++++++++EXPLAIN建议[开始]+++++++++++++++++++++++{
// 如果未配置Online或Test无法给Explain建议 // 如果未配置Online或Test无法给Explain建议
common.Log.Debug("start of explain Query: %s", q.Query)
if !common.Config.OnlineDSN.Disable && !common.Config.TestDSN.Disable { if !common.Config.OnlineDSN.Disable && !common.Config.TestDSN.Disable {
// 因为EXPLAIN依赖数据库环境,所以把这段逻辑放在启发式建议和索引建议后面 // 因为EXPLAIN依赖数据库环境,所以把这段逻辑放在启发式建议和索引建议后面
if common.Config.Explain { if common.Config.Explain {
...@@ -335,6 +340,7 @@ func main() { ...@@ -335,6 +340,7 @@ func main() {
// EXPLAIN阶段给出的ERROR是ERR.002 // EXPLAIN阶段给出的ERROR是ERR.002
mysqlSuggest["ERR.002"] = advisor.RuleMySQLError("ERR.002", err) mysqlSuggest["ERR.002"] = advisor.RuleMySQLError("ERR.002", err)
common.Log.Error("vEnv.Explain Error: %v", err) common.Log.Error("vEnv.Explain Error: %v", err)
continue
} }
} }
// 分析EXPLAIN结果 // 分析EXPLAIN结果
...@@ -345,9 +351,11 @@ func main() { ...@@ -345,9 +351,11 @@ func main() {
} }
} }
} }
common.Log.Debug("end of explain Query: %s", q.Query)
// +++++++++++++++++++++EXPLAIN建议[结束]+++++++++++++++++++++++} // +++++++++++++++++++++EXPLAIN建议[结束]+++++++++++++++++++++++}
// +++++++++++++++++++++Profiling[开始]+++++++++++++++++++++++++{ // +++++++++++++++++++++Profiling[开始]+++++++++++++++++++++++++{
common.Log.Debug("start of profiling Query: %s", q.Query)
if common.Config.Profiling { if common.Config.Profiling {
res, err := vEnv.Profiling(q.Query) res, err := vEnv.Profiling(q.Query)
if err == nil { if err == nil {
...@@ -360,9 +368,11 @@ func main() { ...@@ -360,9 +368,11 @@ func main() {
common.Log.Error("Profiling Error: %v", err) common.Log.Error("Profiling Error: %v", err)
} }
} }
common.Log.Debug("end of profiling Query: %s", q.Query)
// +++++++++++++++++++++Profiling[结束]++++++++++++++++++++++++++} // +++++++++++++++++++++Profiling[结束]++++++++++++++++++++++++++}
// +++++++++++++++++++++Trace [开始]+++++++++++++++++++++++++{ // +++++++++++++++++++++Trace [开始]+++++++++++++++++++++++++{
common.Log.Debug("start of trace Query: %s", q.Query)
if common.Config.Trace { if common.Config.Trace {
res, err := vEnv.Trace(q.Query) res, err := vEnv.Trace(q.Query)
if err == nil { if err == nil {
...@@ -375,9 +385,11 @@ func main() { ...@@ -375,9 +385,11 @@ func main() {
common.Log.Error("Trace Error: %v", err) common.Log.Error("Trace Error: %v", err)
} }
} }
common.Log.Debug("end of trace Query: %s", q.Query)
// +++++++++++++++++++++Trace [结束]++++++++++++++++++++++++++} // +++++++++++++++++++++Trace [结束]++++++++++++++++++++++++++}
// +++++++++++++++++++++SQL重写[开始]+++++++++++++++++++++++++{ // +++++++++++++++++++++SQL重写[开始]+++++++++++++++++++++++++{
common.Log.Debug("start of rewrite Query: %s", q.Query)
if common.Config.ReportType == "rewrite" { if common.Config.ReportType == "rewrite" {
if strings.HasPrefix(strings.TrimSpace(strings.ToLower(sql)), "create") || if strings.HasPrefix(strings.TrimSpace(strings.ToLower(sql)), "create") ||
strings.HasPrefix(strings.TrimSpace(strings.ToLower(sql)), "alter") || strings.HasPrefix(strings.TrimSpace(strings.ToLower(sql)), "alter") ||
...@@ -411,9 +423,11 @@ func main() { ...@@ -411,9 +423,11 @@ func main() {
fmt.Println(strings.TrimSpace(rw.NewSQL)) fmt.Println(strings.TrimSpace(rw.NewSQL))
} }
} }
common.Log.Debug("end of rewrite Query: %s", q.Query)
// +++++++++++++++++++++SQL重写[结束]++++++++++++++++++++++++++} // +++++++++++++++++++++SQL重写[结束]++++++++++++++++++++++++++}
// 打印单条SQL优化建议 // +++++++++++++++++++++打印单条SQL优化建议[开始]++++++++++++++++++++++++++{
common.Log.Debug("start of print suggestions, Query: %s", q.Query)
sug, str := advisor.FormatSuggest(q.Query, common.Config.ReportType, heuristicSuggest, idxSuggest, expSuggest, proSuggest, traceSuggest, mysqlSuggest) sug, str := advisor.FormatSuggest(q.Query, common.Config.ReportType, heuristicSuggest, idxSuggest, expSuggest, proSuggest, traceSuggest, mysqlSuggest)
suggestMerged[id] = sug suggestMerged[id] = sug
switch common.Config.ReportType { switch common.Config.ReportType {
...@@ -443,6 +457,8 @@ func main() { ...@@ -443,6 +457,8 @@ func main() {
default: default:
fmt.Println(str) fmt.Println(str)
} }
common.Log.Debug("end of print suggestions, Query: %s", q.Query)
// +++++++++++++++++++++打印单条SQL优化建议[结束]++++++++++++++++++++++++++}
} }
// 同一张表的多条ALTER语句合并为一条 // 同一张表的多条ALTER语句合并为一条
......
...@@ -23,9 +23,6 @@ func init() { ...@@ -23,9 +23,6 @@ func init() {
// 所有的SQL都要以分号结尾,-list-test-sqls参数会打印这个list,以分号结尾可方便测试 // 所有的SQL都要以分号结尾,-list-test-sqls参数会打印这个list,以分号结尾可方便测试
// 如:./soar -list-test-sql | ./soar // 如:./soar -list-test-sql | ./soar
TestSQLs = []string{ TestSQLs = []string{
// DDL
"create table hello.t (id int unsigned);",
// single equality // single equality
"SELECT * FROM film WHERE length = 86;", // index(length) "SELECT * FROM film WHERE length = 86;", // index(length)
"SELECT * FROM film WHERE length IS NULL;", // index(length) "SELECT * FROM film WHERE length IS NULL;", // index(length)
...@@ -197,5 +194,10 @@ func init() { ...@@ -197,5 +194,10 @@ func init() {
"alter table address add index idx_city_id(city_id);", "alter table address add index idx_city_id(city_id);",
"alter table inventory add index `idx_store_film` (`store_id`,`film_id`);", "alter table inventory add index `idx_store_film` (`store_id`,`film_id`);",
"alter table inventory add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`);", "alter table inventory add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`);",
// https://github.com/XiaoMi/soar/issues/47
`SELECT DATE_FORMAT(t.atm, '%Y-%m-%d'), COUNT(DISTINCT (t.usr)) FROM usr_terminal t WHERE t.atm > '2018-10-22 00:00:00' AND t.agent LIKE '%Chrome%' AND t.system = 'eip' GROUP BY DATE_FORMAT(t.atm, '%Y-%m-%d') ORDER BY DATE_FORMAT(t.atm, '%Y-%m-%d')`,
// https://github.com/XiaoMi/soar/issues/17
"create table hello.t (id int unsigned);",
} }
} }
...@@ -789,6 +789,8 @@ func parseTraditionalExplainText(content string) (explainRows []*ExplainRow, err ...@@ -789,6 +789,8 @@ func parseTraditionalExplainText(content string) (explainRows []*ExplainRow, err
if err != nil { if err != nil {
filtered = 0.00 filtered = 0.00
} }
// filtered may larger than 100.00
// https://bugs.mysql.com/bug.php?id=34124
if filtered > 100.00 { if filtered > 100.00 {
filtered = 100.00 filtered = 100.00
} }
...@@ -981,7 +983,7 @@ func ParseExplainResult(res *QueryResult, formatType int) (exp *ExplainInfo, err ...@@ -981,7 +983,7 @@ func ParseExplainResult(res *QueryResult, formatType int) (exp *ExplainInfo, err
// Explain 获取SQL的explain信息 // Explain 获取SQL的explain信息
func (db *Connector) Explain(sql string, explainType int, formatType int) (exp *ExplainInfo, err error) { func (db *Connector) Explain(sql string, explainType int, formatType int) (exp *ExplainInfo, err error) {
exp = &ExplainInfo{} exp = &ExplainInfo{SQL: sql}
if explainType != TraditionalExplainType { if explainType != TraditionalExplainType {
formatType = TraditionalFormatExplain formatType = TraditionalFormatExplain
} }
...@@ -1004,8 +1006,6 @@ func (db *Connector) Explain(sql string, explainType int, formatType int) (exp * ...@@ -1004,8 +1006,6 @@ func (db *Connector) Explain(sql string, explainType int, formatType int) (exp *
// 解析mysql结果,输出ExplainInfo // 解析mysql结果,输出ExplainInfo
exp, err = ParseExplainResult(res, formatType) exp, err = ParseExplainResult(res, formatType)
// 补全SQL
exp.SQL = sql
return exp, err return exp, err
} }
......
...@@ -7,7 +7,7 @@ SOAR主要由语法解析器,集成环境,优化建议,重写逻辑,工 ...@@ -7,7 +7,7 @@ SOAR主要由语法解析器,集成环境,优化建议,重写逻辑,工
## 语法解析和语法检查 ## 语法解析和语法检查
一条SQL从文件,标准输入或命令行参数等形式传递给SOAR后首先进入语法解析器,这里一开始我们选用了vitess的语法解析库作为SOAR的语法解析库,但随时需求的不断增加我们发现有些复杂需求使用vitess的语法解析实现起来比较逻辑比较复杂。于是参考业其他数据库产品,我们引入了TiDB的语法解析器做为补充。我们发现这两个解析库还存在一定的盲区,于是又引入了MySQL执行返回结果作为多版本SQL方言的补充。大家也可以看到在语法解析器这里,SOAR的实现方案是松散的、可插拔的。SOAR并不直接维护庞大的语法解析库,它把各种优秀的语法解析库集成在一起,各取所长。 一条SQL从文件,标准输入或命令行参数等形式传递给SOAR后首先进入语法解析器,这里一开始我们选用了vitess的语法解析库作为SOAR的语法解析库,但随时需求的不断增加我们发现有些复杂需求使用vitess的语法解析实现起来比较逻辑比较复杂。于是参考业其他数据库产品,我们引入了TiDB的语法解析器做为补充。我们发现这两个解析库还存在一定的盲区,于是又引入了MySQL执行返回结果作为多版本SQL方言的补充。大家也可以看到在语法解析器这里,SOAR的实现方案是松散的、可插拔的。SOAR并不直接维护庞大的语法解析库,它把各种优秀的语法解析库集成在一起,各取所长。
## 集成环境 ## 集成环境
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册