MySQL的隐藏功能

时间:2008-12-15 16:09:58

标签: mysql database hidden-features

我多年来一直与Microsoft SQL Server合作,但最近才开始在我的网络应用程序中使用MySQL,而且我渴望知识。

继续"hidden feature" questions的长行,我想知道MySQL的任何隐藏或方便的功能,这将有望提高我对这个开源数据库的了解。

20 个答案:

答案 0 :(得分:161)

答案 1 :(得分:22)

MySQL的一个不那么隐藏的功能是,它不是真的很擅长SQL兼容,好吧,不是真的错误,但是,更多gotchas ...: - )

答案 2 :(得分:21)

找出当前缓存中的表的命令:

mysql> SHOW open TABLES FROM test;
+----------+-------+--------+-------------+
| DATABASE | TABLE | In_use | Name_locked |
+----------+-------+--------+-------------+
| test     | a     |      3 |           0 |
+----------+-------+--------+-------------+
1 row IN SET (0.00 sec)

(来自MySQL performance blog

答案 3 :(得分:15)

找出谁在做什么的命令:

mysql> show processlist;
show processlist;
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
| Id | User        | Host            | db   | Command | Time | State                            | Info             |
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
|  1 | root        | localhost:32893 | NULL | Sleep   |    0 |                                  | NULL             |
|  5 | system user |                 | NULL | Connect |   98 | Waiting for master to send event | NULL             |
|  6 | system user |                 | NULL | Connect | 5018 | Reading event from the relay log | NULL             |
+-----+------+-----------+---------+---------+-------+-------+------------------+
3 rows in set (0.00 sec) 

您可以使用以下命令终止进程:

mysql>kill 5 

答案 4 :(得分:11)

我特别喜欢MySQL对inet_ntoa()inet_aton()的内置支持。它使表中的IP地址处理变得非常简单(至少只要它们只是IPv4地址!)

答案 5 :(得分:11)

我喜欢on duplicate key(AKA upsert,merge)为懒惰创建的各种计数器:

insert into occurances(word,count) values('foo',1),('bar',1) 
  on duplicate key cnt=cnt+1

您可以在一个查询中插入多行,并立即处理每个行的重复索引。

答案 6 :(得分:10)

再次 - 不是真正隐藏的功能,但非常方便:

<强>功能

轻松抓住DDL:

SHOW CREATE TABLE CountryLanguage

输出:

CountryLanguage | CREATE TABLE countrylanguage (
  CountryCode char(3) NOT NULL DEFAULT '',
  Language char(30) NOT NULL DEFAULT '',
  IsOfficial enum('T','F') NOT NULL DEFAULT 'F',
  Percentage float(4,1) NOT NULL DEFAULT '0.0',
  PRIMARY KEY (CountryCode,Language)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

功能:GROUP_CONCAT()聚合函数 每个细节创建其参数的串联字符串,并通过连接每个组进行聚合。

示例1:简单

SELECT   CountryCode
,        GROUP_CONCAT(Language) AS List
FROM     CountryLanguage
GROUP BY CountryCode             

输出:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | Dutch,English,Papiamento,Spanish   |
. ...         . ...                                .
| ZWE         | English,Ndebele,Nyanja,Shona       |
+-------------+------------------------------------+

示例2:多个参数

SELECT   CountryCode
,        GROUP_CONCAT(
             Language
,            IF(IsOfficial='T', ' (Official)', '')
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

输出:

+-------------+---------------------------------------------+
| CountryCode | List                                        |
+-------------+---------------------------------------------+
| ABW         | Dutch (Official),English,Papiamento,Spanish |
. ...         . ...                                         .
| ZWE         | English (Official),Ndebele,Nyanja,Shona     |
+-------------+---------------------------------------------+

示例3:使用自定义分隔符

SELECT   CountryCode
,        GROUP_CONCAT(Language SEPARATOR ' and ') AS List
FROM     CountryLanguage
GROUP BY CountryCode

输出:

+-------------+----------------------------------------------+
| CountryCode | List                                         |
+-------------+----------------------------------------------+
| ABW         | Dutch and English and Papiamento and Spanish |
. ...         . ...                                          .
| ZWE         | English and Ndebele and Nyanja and Shona     |
+-------------+----------------------------------------------+

示例4:控制列表元素的顺序

SELECT   CountryCode
,        GROUP_CONCAT(
         Language
         ORDER BY CASE IsOfficial WHEN 'T' THEN 1 ELSE 2 END DESC
         ,        Language
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

输出:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | English,Papiamento,Spanish,Dutch,  |
. ...         . ...                                .
| ZWE         | Ndebele,Nyanja,Shona,English       |
+-------------+------------------------------------+

功能:包含多个表达式的COUNT(DISTINCT)

您可以在COUNT(DISTINCT ...)表达式中使用多个表达式来计算组合数。

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

功能/陷阱:无需在GROUP BY列表中包含非聚合表达

大多数RDBMS-es强制执行符合SQL92的GROUP BY,这要求SELECT列表中的所有非聚合表达式都出现在GROUP BY中。在这些RDBMS中,这句话:

SELECT     Country.Code, Country.Continent, COUNT(CountryLanguage.Language)
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

无效,因为SELECT列表包含未出现在GROUP BY列表中的非聚合列Country.Continent。在这些RDBMS中,您必须修改GROUP BY列表以读取

GROUP BY   Country.Code, Country.Continent

或者您必须向Country.Continent添加一些无意义的聚合,例如

SELECT     Country.Code, MAX(Country.Continent), COUNT(CountryLanguage.Language)

现在,问题是,逻辑上没有任何东西要求Country.Continent应该进行聚合。请参阅Country.Code是Country表的主键。 Country.Continent也是Country表中的一列,因此在功能上依赖于主键Country.Code的定义。因此,对于每个不同的Country.Code,Country.Continent中必须只存在一个值。如果你意识到这一点,那么你就会意识到聚合它是没有意义的(只有一个值,正确),也不是按它分组(因为它不会使结果更加独特,因为你已经分组了pk)

无论如何 - MySQL允许您在SELECT列表中包含非聚合列,而无需将它们也添加到GROUP BY子句中。

问题在于,如果您碰巧使用非聚合列,MySQL不会保护您。所以,像这样的查询:

SELECT     Country.Code, COUNT(CountryLanguage.Language), CountryLanguage.Percentage
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

将在没有投诉的情况下执行,但CountryLanguage.Percentage列将包含无意义(也就是说,在所有语言百分比中,百分比的其中一个可用值将随机选取或至少在您控制之外

请参阅:Debunking Group By Myths

答案 7 :(得分:7)

客户端中的“pager”命令

如果您的结果中有10,000行,并希望查看它们(这假定“less”和“tee”命令可用,这通常是在Linux下的情况;在Windows YMMV中。)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

你会在“较少”的文件查看器中获取它们,这样你就可以很好地浏览它们,搜索等。

另外

pager tee myfile.txt
select a_few_things FROM tbl WHERE i_want_to_save_output_to_a_file;

将方便地写入文件。

答案 8 :(得分:6)

有些事情你可能会感兴趣:

<query>\G -- \G in the CLI instead of the ; will show one column per row
explain <query>; -- this will show the execution plan for the query

答案 9 :(得分:4)

不是隐藏的功能,但仍然有用:http://mtop.sourceforge.net/

答案 10 :(得分:3)

如果使用cmdline Mysq,您可以使用尖叫/感叹号与命令行进行交互(在Linux机器上 - 不确定是否对Windows有相同的效果)。例如:

\! cat file1.sql

将显示file1.sql的代码。要将语句和查询保存到文件,请使用tee facility

\T filename

将其关闭使用\ t

最后要运行已保存的脚本,请使用“source filename”。当然,正常的替代方法是在从命令行启动mysql时指向脚本名称:

    mysql -u root -p < case1.sql

希望对某人有用!

编辑:只记得另一个 - 当从命令行调用mysql时,你可以使用-t开关,使输出为表格格式 - 带有一些查询的真正好处(虽然当然用其他地方提到的\ G终止查询)这方面也有帮助)。关于各种开关Command Line Tool

的更多内容

刚刚找到一种改变排序顺序的简洁方法(通常使用Case ...) 如果要更改排序顺序(可能按1,4,3,2而不是1,2,3,4排序),可以使用Order by子句中的字段函数。 例如

按字段排序(sort_field,1,4,3,2)

答案 11 :(得分:3)

我认为这不是针对MySQL的,而是让我感到高兴:

而不是写

WHERE (x.id > y.id) OR (x.id = y.id AND x.f2 > y.f2) 

你可以写

WHERE (x.id, x.f2) > (y.id, y.f2)

答案 12 :(得分:3)

如果您打算使用大型和/或高交易量的InnoDb数据库来学习和理解“SHOW INNODB STATUS”Mysql Performance Blog,它将成为您的朋友。

答案 13 :(得分:3)

以下是我的一些提示 - 我在博客上发表了关于他们的博文(Link

  1. 在声明变量时,您不需要使用“@”符号。
  2. 您必须使用分隔符(默认为';')来划分语句的结尾 - Link
  3. 如果您尝试在MS-SQL 2005和mySQL之间移动数据,可以跳过几个环节 - Link
  4. 在mySQL中执行区分大小写的匹配 - link

答案 14 :(得分:2)

mysqlsla - 最常用的慢查询日志分析工具之一。自上次推出慢查询日志以来,您可以看到前10个重要查询。它还可以告诉您BAD查询被触发的次数以及它在服务器上花费的总时间。

答案 15 :(得分:2)

实际上是documented,但非常烦人:错误日期和其他错误输入的自动转换。

  

在MySQL 5.0.2之前,MySQL可以容忍非法或不正确的数据值,并强制它们为数据输入的合法值。在MySQL 5.0.2及更高版本中,这仍然是默认行为,但您可以更改服务器SQL模式以选择更传统的错误值处理方式,以便服务器拒绝它们并中止它们出现的语句。

至于日期:当MySQL没有将输入调整到附近的有效日期时,有时你会“幸运”,而是将其存储为0000-00-00,根据定义,它是无效的。但是,即便如此,您可能希望MySQL失败,而不是默默地为您存储此值。

答案 16 :(得分:2)

内置SQL Profiler

答案 17 :(得分:1)

默认情况下,InnoDB将所有表存储在一个全局表空间中,永不缩小

您可以使用innodb_file_per_table将每个表放在一个单独的表空间中,当您删除表或数据库时,这些表空间将被删除。

提前计划,因为你必须转储和恢复数据库,否则回收空间。

Using Per-Table Tablespaces

答案 18 :(得分:1)

如果在datetime列中插入空字符串值“”,MySQL将保留该值为00/00/0000 00:00:00。与Oracle不同,后者将保存空值。

答案 19 :(得分:1)

在使用大型数据集和DATETIME字段的基准测试期间,执行此查询的速度总是较慢:

SELECT * FROM mytable
WHERE date(date_colum) BETWEEN '2011-01-01' AND ''2011-03-03';

比这种方法:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'