cases.go 13.4 KB
Newer Older
martianzhang's avatar
martianzhang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
/*
 * Copyright 2018 Xiaomi, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package common

// TestSQLs 测试SQL大集合
var TestSQLs []string

func init() {
	// 所有的SQL都要以分号结尾,-list-test-sqls参数会打印这个list,以分号结尾可方便测试
	// 如:./soar -list-test-sql | ./soar
	TestSQLs = []string{
		//  single equality
		"SELECT * FROM film WHERE length = 86;",    // index(length)
		"SELECT * FROM film WHERE length IS NULL;", // index(length)
		"SELECT * FROM film HAVING title = 'abc';", // 无法使用索引

		//single inequality
		"SELECT * FROM sakila.film WHERE length >= 60;",   // any of <, <=, >=, >; but not <>, !=, IS NOT NULL"
		"SELECT * FROM sakila.film WHERE length >= '60';", // Implicit Conversion
		"SELECT * FROM film WHERE length BETWEEN 60 AND 84;",
		"SELECT * FROM film WHERE title LIKE 'AIR%';", // but not LIKE '%blah'",
		"SELECT * FROM film WHERE title IS NOT NULL;",

		// multiple equalities
		"SELECT * FROM film WHERE length = 114 and title = 'ALABAMA DEVIL';", // index(title,length) or index(length,title)",

		// equality and inequality
		"SELECT * FROM film WHERE length > 100 and title = 'ALABAMA DEVIL';", // index(title, length)",

		// multiple inequality
		"SELECT * FROM film WHERE length > 100 and language_id < 10 and title = 'xyz';", // index(d, b) or index(d, c) 依赖数据",
		"SELECT * FROM film WHERE length > 100 and language_id < 10;",                   // index(b) or index(c)",

		// GROUP BY
		"SELECT release_year, sum(length) FROM film WHERE length = 123 AND language_id = 1 GROUP BY release_year;",  // INDEX(length, language_id, release_year) or INDEX(language_id, length, release_year)",
		"SELECT release_year, sum(length) FROM film WHERE length >= 123 GROUP BY release_year;",                     // INDEX(length)",
		"SELECT release_year, language_id, sum(length) FROM film GROUP BY release_year, language_id;",               // INDEX(release_year, language_id) (no WHERE)",
		"SELECT release_year, sum(length) FROM film WHERE length = 123 GROUP BY release_year,(length+language_id);", // INDEX(length) expression in GROUP BY, so no use including even release_year.",
		"SELECT release_year, sum(film_id) FROM film GROUP BY release_year;",                                        // INDEX(`release_year`)
		"SELECT * FROM address GROUP BY address,district;",                                                          // INDEX(address, district)
		"SELECT title FROM film WHERE ABS(language_id) = 3 GROUP BY title;",                                         // 无法使用索引

		// ORDER BY
		"SELECT language_id FROM film WHERE length = 123 GROUP BY release_year ORDER BY language_id;",            //  INDEX(length, release_year) should have stopped with Step 2b",
		"SELECT release_year FROM film WHERE length = 123 GROUP BY release_year ORDER BY release_year;",          //  INDEX(length, release_year) the release_year will be used for both GROUP BY and ORDER BY",
		"SELECT * FROM film WHERE length = 123 ORDER BY release_year ASC, language_id DESC;",                     //  INDEX(length) mixture of ASC and DESC.",
		"SELECT release_year FROM film WHERE length = 123 GROUP BY release_year ORDER BY release_year LIMIT 10;", //  INDEX(length, release_year)",
		"SELECT * FROM film WHERE length = 123 ORDER BY release_year LIMIT 10;",                                  //  INDEX(length, release_year)",
		"SELECT * FROM film ORDER BY release_year LIMIT 10;",                                                     //  INDEX(release_year)",
		"SELECT * FROM film WHERE length > 100 ORDER BY length LIMIT 10;",                                        //  INDEX(length) This "range" is compatible with ORDER BY
		"SELECT * FROM film WHERE length < 100 ORDER BY length LIMIT 10;",                                        //  INDEX(length) also works
		"SELECT * FROM customer WHERE address_id in (224,510) ORDER BY last_name;",                               // INDEX(address_id)
		"SELECT * FROM film WHERE release_year = 2016 AND length != 1 ORDER BY title;",                           // INDEX(`release_year`, `length`, `title`)

		//"Covering" IdxRows
		"SELECT title FROM film WHERE release_year = 1995;",                               //  INDEX(release_year, title)",
		"SELECT title, replacement_cost FROM film WHERE language_id = 5 AND length = 70;", //  INDEX(language_id, length, title, replacement_cos film ), title, replacement_cost顺序无关,language_id, length顺序视散粒度情况.
		"SELECT title FROM film WHERE language_id > 5 AND length > 70;",                   //  INDEX(language_id, length, title) language_id or length first (that's as far as the Algorithm goes), then the other two fields afterwards.

		// equalities and sort
		"SELECT * FROM film WHERE length = 100 and title = 'xyz' ORDER BY release_year;", // 依赖数据特征,index(length, title, release_year) or index(title, length, release_year)需要评估

		// inequality and sort
		"SELECT * FROM film WHERE length > 100 and title = 'xyz' ORDER BY release_year;", // 依赖数据特征, index(title, release_year),index(title, length)需要评估
		"SELECT * FROM film WHERE length > 100 ORDER BY release_year;",                   // 依赖数据特征, index(length),index(release_year)需要评估

		// Join
		// 内连接 INNER JOIN
		// 在mysql中,inner join...on , join...on , 逗号...WHERE ,cross join...on是一样的含义。
		// 但是在标准SQL中,它们并不等价,标准SQL中INNER JOIN与ON共同使用, CROSS JOIN用于其他情况。
		// 逗号不支持on和using语法, 逗号的优先级要低于INNER JOIN, CROSS JOIN, LEFT JOIN
		// ON子句的语法格式为:tb1.col1 = tb2.col2列名可以不同,筛选连接后的结果,两表的对应列值相同才在结果集中。
		// 当模式设计对联接表的列采用了相同的命名样式时,就可以使用 USING 语法来简化 ON 语法

		// join, inner join, cross join等价,优先选择小结果集条件表为驱动表
		// left [outer] join左表为驱动表
		// right [outer] join右表为驱动表
		// 驱动表连接列如果没其他条件可以不考虑加索引,反正是需要foreach
		// 被驱动表连接列需要加索引。即:left [outer] join的右表连接列需要加索引,right [outer] join的左表连接列需要加索引,inner join结果集较大表的连接列需要加索引
		// 其他索引添加算法与单表索引优化算法相同
		// 总结:被驱动表列需要添加索引
		// 建议:将无索引的表通常作为驱动表

		"SELECT * FROM city a INNER JOIN country b ON a.country_id=b.country_id;",

		// 左外连接 LEFT [OUTER] JOIN
		"SELECT * FROM city a LEFT JOIN country b ON a.country_id=b.country_id;",

		// 右外连接 RIGHT [OUTER] JOIN
		"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 RIGHT JOIN country b ON a.country_id=b.country_id WHERE a.last_update IS NULL;",

		// 全连接 FULL JOIN 因为在mysql中并不支持,所以我们用union实现
		"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;",

		// NATURAL JOIN 默认是同名字段完全匹配的INNER JOIN
		"SELECT country_id, last_update FROM city NATURAL JOIN country;",

		// NATURAL LEFT JOIN
		"SELECT country_id, last_update FROM city NATURAL LEFT JOIN country;",

		// NATURAL RIGHT JOIN
		"SELECT country_id, last_update FROM city NATURAL RIGHT JOIN country;",

		// STRAIGHT_JOIN 实际上与内连接 INNER JOIN 表现完全一致,
		// 不同的是使用了 STRAIGHT_JOIN后指定表载入的顺序,city先于country载入
		"SELECT a.country_id, a.last_update FROM city a STRAIGHT_JOIN country b ON a.country_id=b.country_id;",

		// SEMI JOIN
		// 半连接: 当一张表在另一张表找到匹配的记录之后,半连接(semi-join)返回第一张表中的记录。
		// 与条件连接相反,即使在右节点中找到几条匹配的记录,左节点的表也只会返回一条记录。
		// 另外,右节点的表一条记录也不会返回。半连接通常使用IN  或 EXISTS 作为连接条件
		"SELECT d.deptno,d.dname,d.loc FROM scott.dept d WHERE d.deptno IN  (SELECT e.deptno FROM scott.emp e);",

		// Delayed Join
		// https://www.percona.com/blog/2007/04/06/using-delayed-join-to-optimize-count-and-limit-queries/
		`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
		"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 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 film WHERE length > 100;",

		// UPDATE
		"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, 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;",

		// INSERT
		"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 (10);",
		"INSERT INTO city (country_id) SELECT 10 FROM DUAL;",

		// REPLACE
		"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 (10);",
		"REPLACE INTO city (country_id) SELECT 10 FROM DUAL;",

		// DEPTH
		"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;",

		// SUBQUERY
		"SELECT * FROM film WHERE language_id = (SELECT language_id FROM language LIMIT 1);",
		//"SELECT COUNT(*) /* no hint */ FROM t2 WHERE NOT EXISTS (SELECT * FROM t3 WHERE ROW(5 * t2.s1, 77) = (SELECT 50, 11 * s1 FROM t4 UNION SELECT 50, 77 FROM (SELECT * FROM t5) AS t5 ) ) ;",
		"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 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 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;",

		// function in conditions
		"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 order by date(last_update);",

		// CLA.004
		"SELECT description FROM film WHERE description IN('NEWS','asd') GROUP BY description;",

		// ALTER TABLE ADD INDEX
		// 已经存在索引的列应该提醒索引已存在
		"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`),add index `idx_store_film` (`store_id`,`film_id`),add index `idx_store_film` (`store_id`,`film_id`);",
	}
}