SELECT

SELECT 语句用于从 TiDB 读取数据。

语法图

SelectStmt:

SelectStmt

FromDual:

FromDual

WhereClauseOptional:

WhereClauseOptional

SelectStmtOpts:

SelectStmtOpts

SelectStmtFieldList:

SelectStmtFieldList

TableRefsClause:

TableRefsClause

SELECT - 图6

AsOfClause

SELECT - 图7

  1. TableRefsClause ::=
  2. TableRef AsOfClause? ( ',' TableRef AsOfClause? )*
  3. AsOfClause ::=
  4. 'AS' 'OF' 'TIMESTAMP' Expression

SelectStmtGroup:

SelectStmtGroup

HavingClause:

HavingClause

OrderByOptional:

OrderByOptional

SelectStmtLimit:

SelectStmtLimit

FirstOrNext:

FirstOrNext

FetchFirstOpt:

FetchFirstOpt

RowOrRows:

RowOrRows

SelectLockOpt:

SelectLockOpt

SELECT - 图15

TableList

SELECT - 图16

  1. SelectLockOpt ::=
  2. ( ( 'FOR' 'UPDATE' ( 'OF' TableList )? 'NOWAIT'? )
  3. | ( 'LOCK' 'IN' 'SHARE' 'MODE' ) )?
  4. TableList ::=
  5. TableName ( ',' TableName )*

WindowClauseOptional

WindowClauseOptional

TableSampleOpt

TableSampleOpt

SELECT - 图18

  1. TableSampleOpt ::=
  2. 'TABLESAMPLE' 'REGIONS()'

语法元素说明

语法元素说明
TableOptimizerHints用于控制优化器行为的 Hint,具体可参见 Optimizer Hints
ALLDISTINCTDISTINCTROW查询结果集中可能会包含重复值。指定 DISTINCT/DISTINCTROW 则在查询结果中过滤掉重复的行;指定 ALL 则列出所有的行。默认为 ALL。
HIGH_PRIORITY该语句为高优先级语句,TiDB 在执行阶段会优先处理这条语句
SQL_CALC_FOUND_ROWSTiDB 不支持该语法,并报错(若 tidb_enable_noop_functions 值设为 1 则不会报错)
SQL_CACHESQL_NO_CACHE是否把请求结果缓存到 TiKV (RocksDB) 的 BlockCache 中。对于一次性的大数据量的查询,比如 count() 查询,为了避免冲掉 BlockCache 中用户的热点数据,建议填上 SQL_NO_CACHE
STRAIGHT_JOINSTRAIGHT_JOIN 会强制优化器按照 FROM 子句中所使用的表的顺序做联合查询。当优化器选择的 Join 顺序并不优秀时,你可以使用这个语法来加速查询的执行
select_expr投影操作列表,一般包括列名、表达式,或者是用 ‘‘ 表示全部列
FROM table_references表示数据来源,数据来源可以是一个表 (select from t;) 或者是多个表 (select from t1 join t2;) 或者是 0 个表(select 1+1 from dual;,等价于 select 1+1;
WHERE where_conditionWhere 子句用于设置过滤条件,查询结果中只会包含满足条件的数据
GROUP BYGroupBy 子句用于对查询结果集进行分组
HAVING where_conditionHaving 子句与 Where 子句作用类似,Having 子句可以让过滤 GroupBy 后的各种数据,Where 子句用于在聚合前过滤记录。
ORDER BYOrderBy 子句用于指定结果排序顺序,可以按照列、表达式或者是 select_expr 列表中某个位置的字段进行排序。
LIMITLimit 子句用于限制结果条数。Limit 接受一个或两个数字参数,如果只有一个参数,那么表示返回数据的最大行数;如果是两个参数,那么第一个参数表示返回数据的第一行的偏移量(第一行数据的偏移量是 0),第二个参数指定返回数据的最大条目数。另支持 FETCH FIRST/NEXT n ROW/ROWS ONLY 语法,与 LIMIT n 效果相同,其中 n 可省略,省略时与 LIMIT 1 效果相同。
Window window_definition窗口函数的相关语法,用来进行一些分析型计算的操作,详情可见窗口函数
FOR UPDATE对查询结果集所有行上锁(对于在查询条件内,但是不在结果集的行,将不会加锁,如事务启动后由其他事务写入的行),以监测其他事务对这些的并发修改。当 TiDB 使用乐观事务模型时,语句执行期间不会检测锁,因此,不会像 PostgreSQL 之类的数据库一样,在当前事务结束前阻止其他事务执行 UPDATEDELETESELECT FOR UPDATE。在事务的提交阶段 SELECT FOR UPDATE 读到的行,也会进行两阶段提交,因此,它们也可以参与事务冲突检测。如发生写入冲突,那么包含 SELECT FOR UPDATE 语句的事务会提交失败。如果没有冲突,事务将成功提交,当提交结束时,这些被加锁的行,会产生一个新版本,可以让其他尚未提交的事务,在将来提交时发现写入冲突。当 TiDB 使用悲观事务模型时,其行为与其他数据库基本相同,不一致之处参考和 MySQL InnoDB 的差异。TiDB 支持 FOR UPDATE NOWAIT 语法,详情可见 TiDB 中悲观事务模式的行为
LOCK IN SHARE MODETiDB 出于兼容性解析这个语法,但是不做任何处理
TABLESAMPLE从表中获取一些行的样本数据。

示例

SELECT

  1. CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, c1 INT NOT NULL);
  1. Query OK, 0 rows affected (0.11 sec)
  1. INSERT INTO t1 (c1) VALUES (1),(2),(3),(4),(5);
  1. Query OK, 5 rows affected (0.03 sec)
  2. Records: 5 Duplicates: 0 Warnings: 0
  1. SELECT * FROM t1;
  1. +----+----+
  2. | id | c1 |
  3. +----+----+
  4. | 1 | 1 |
  5. | 2 | 2 |
  6. | 3 | 3 |
  7. | 4 | 4 |
  8. | 5 | 5 |
  9. +----+----+
  10. 5 rows in set (0.00 sec)

下面这个例子使用 tiup bench tpcc prepare 生成的数据,其中第一个查询展示了 TABLESAMPLE 的用法。

  1. mysql> SELECT AVG(s_quantity), COUNT(s_quantity) FROM stock TABLESAMPLE REGIONS();
  2. +-----------------+-------------------+
  3. | AVG(s_quantity) | COUNT(s_quantity) |
  4. +-----------------+-------------------+
  5. | 59.5000 | 4 |
  6. +-----------------+-------------------+
  7. 1 row in set (0.00 sec)
  8. mysql> SELECT AVG(s_quantity), COUNT(s_quantity) FROM stock;
  9. +-----------------+-------------------+
  10. | AVG(s_quantity) | COUNT(s_quantity) |
  11. +-----------------+-------------------+
  12. | 54.9729 | 1000000 |
  13. +-----------------+-------------------+
  14. 1 row in set (0.52 sec)

SELECT … INTO OUTFILE

SELECT ... INTO OUTFILE 语句用于将查询结果写入到文件中。

SELECT - 图19

注意

该语句不支持将查询结果写入任何外部存储,如 Amazon S3 或 GCS。

在该语句中,你可以使用以下子句来指定输出文件的格式:

  • FIELDS TERMINATED BY:指定文件中字段的分隔符。例如,你可以将分隔符指定为 ',' 以输出逗号分隔值(CSV)或 '\t' 以输出制表符分隔值(TSV)。
  • FIELDS ENCLOSED BY:指定文件中包裹每个字段的字符。
  • LINES TERMINATED BY:如果你希望以某个特殊的字符为结尾来切分行数据,可以使用该子句指定文件中行的终止符。

假设有一个名为 t 的表,包含以下三列:

  1. mysql> CREATE TABLE t (a INT, b VARCHAR(10), c DECIMAL(10,2));
  2. Query OK, 0 rows affected (0.02 sec)
  3. mysql> INSERT INTO t VALUES (1, 'a', 1.1), (2, 'b', 2.2), (3, 'c', 3.3);
  4. Query OK, 3 rows affected (0.01 sec)

以下示例展示了如何使用 SELECT ... INTO OUTFILE 语句将查询结果写入到文件中。

示例 1:

  1. mysql> SELECT * FROM t INTO OUTFILE '/tmp/tmp_file1';
  2. Query OK, 3 rows affected (0.00 sec)

在此示例中,你可以在 /tmp/tmp_file1 中看到以下查询结果:

  1. 1 a 1.10
  2. 2 b 2.20
  3. 3 c 3.30

示例 2:

  1. mysql> SELECT * FROM t INTO OUTFILE '/tmp/tmp_file2' FIELDS TERMINATED BY ',' ENCLOSED BY '"';
  2. Query OK, 3 rows affected (0.00 sec)

在此示例中,你可以在 /tmp/tmp_file2 中看到以下查询结果:

  1. "1","a","1.10"
  2. "2","b","2.20"
  3. "3","c","3.30"

示例 3:

  1. mysql> SELECT * FROM t INTO OUTFILE '/tmp/tmp_file3'
  2. -> FIELDS TERMINATED BY ',' ENCLOSED BY '\'' LINES TERMINATED BY '<<<\n';
  3. Query OK, 3 rows affected (0.00 sec)

在此示例中,你可以在 /tmp/tmp_file3 中看到以下查询结果:

  1. '1','a','1.10'<<<
  2. '2','b','2.20'<<<
  3. '3','c','3.30'<<<

MySQL 兼容性

  • 不支持 SELECT ... INTO @variable 语法。
  • 不支持 SELECT ... INTO DUMPFILE 语法。
  • 不支持 MySQL 5.7 中支持的 SELECT .. GROUP BY expr 语法,而是匹配 MySQL 8.0 的行为,不按照默认的顺序进行排序。
  • SELECT ... TABLESAMPLE ... 是 TiDB 的扩展语法,用于兼容其他数据库以及 ISO/IEC 9075-2 标准,但 MySQL 不支持该语法。

另请参阅