MySQL的隐藏功能

Gat*_*ler 101 mysql database hidden-features

我已经使用Microsoft SQL Server多年了,但最近才开始在我的Web应用程序中使用MySQL,而且我渴望知识.

为了继续使用长长的"隐藏功能"问题,我想知道MySQL的任何隐藏或方便的功能,这将有望提高我对这个开源数据库的了解.

Mik*_*der 161

既然你拿出了赏金,我将分享我辛苦的秘密......

通常,我今天调整的所有SQL都需要使用子查询.来自Oracle数据库世界,我认为理所当然的事情与MySQL不同.我对MySQL调优的阅读使我得出结论,MySQL在优化查询方面落后于Oracle.

虽然大多数B2C应用程序所需的简单查询可能适用于MySQL,但智能报告所需的大多数报告类型的查询似乎需要进行相当多的规划和重新组织SQL查询,以指导MySQL更快地执行它们.

管理:

max_connections是并发连接的数量.默认值为100个连接(自5.0以来为151) - 非常小.

注意:

连接占用内存,您的操作系统可能无法处理大量连接.

Linux/x86的MySQL二进制文件允许您拥有多达4096个并发连接,但自编译的二进制文件通常具有较少的限制.

设置table_cache以匹配打开的表和并发连接的数量.观察open_tables值,如果它快速增长,则需要增加其大小.

注意:

之前的2个参数可能需要大量打开的文件.20 + max_connections + table_cache*2是您需要的一个很好的估计.Linux上的MySQL有一个open_file_limit选项,设置此限制.

如果您有复杂的查询,sort_buffer_size和tmp_table_size可能非常重要.值取决于查询复杂性和可用资源,但分别是4Mb和32Mb是推荐的起始点.

注意:这些是read_buffer_size,read_rnd_buffer_size和其他一些中的"每个连接"值,这意味着每个连接可能需要此值.因此,在设置这些参数时,请考虑您的负载和可用资源.例如,仅当MySQL需要进行排序时才分配sort_buffer_size.注意:注意不要耗尽内存.

如果您建立了许多连接(即没有持久连接的网站),则可以通过将thread_cache_size设置为非零值来提高性能.16是很有价值的开始.增加值,直到threads_created不会快速增长.

首要的关键:

每个表只能有一个AUTO_INCREMENT列,必须将其编入索引,并且不能具有DEFAULT值

KEY通常是INDEX的同义词.当在列定义中给出时,键属性PRIMARY KEY也可以被指定为KEY.这是为了与其他数据库系统兼容而实现的.

PRIMARY KEY是一个唯一索引,其中所有键列必须定义为NOT NULL

如果PRIMARY KEY或UNIQUE索引只包含一个具有整数类型的列,则还可以在SELECT语句中将该列称为"_rowid".

在MySQL中,PRIMARY KEY的名称是PRIMARY

目前,只有InnoDB(v5.1?)表支持外键.

通常,您在创建表时创建所需的所有索引.声明为PRIMARY KEY,KEY,UNIQUE或INDEX的任何列都将被编入索引.

NULL表示"没有值".要测试NULL,不能使用算术比较运算符,例如=,<或<>.改为使用IS NULL和IS NOT NULL运算符:

NO_AUTO_VALUE_ON_ZERO禁止0的自动递增,以便只有NULL生成下一个序列号.如果0已存储在表的AUTO_INCREMENT列中,则此模式非常有用.(顺便说一句,存储0不是推荐的做法.)

要更改要用于新行的AUTO_INCREMENT计数器的值,请执行以下操作:

ALTER TABLE mytable AUTO_INCREMENT = value; 
Run Code Online (Sandbox Code Playgroud)

或SET INSERT_ID = value;

除非另有说明,否则该值将以:1000000开头或指定:

...)ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 1

戳:

TIMESTAMP列的值从当前时区转换为UTC以进行存储,并从UTC转换为当前时区以进行检索.

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html 对于表中的一个TIMESTAMP列,您可以将当前时间戳指定为默认值和自动更新值.

在WHERE子句中使用其中一种类型时要注意的一件事是,最好做WHERE datecolumn = FROM_UNIXTIME(1057941242)而不是WHERE UNIX_TIMESTAMP(datecolumn)= 1057941242.做后者不会利用索引在那一栏上.

http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

 UNIX_TIMESTAMP() 
 FROM_UNIXTIME() 
 UTC_DATE()
 UTC_TIME()
 UTC_TIMESTAMP()
Run Code Online (Sandbox Code Playgroud)

如果你在MySQL
中将日期时间转换为unix时间戳:然后再添加24小时:
然后将其转换回日期时间,它会神奇地失去一小时!

这是正在发生的事情.将unix时间戳转换回日期时间时考虑了时区,恰好在2006年10月28日到29日之间我们节省了夏令时并且损失了一个小时.

从MySQL 4.1.3开始,CURRENT_TIMESTAMP(),CURRENT_TIME(),CURRENT_DATE()和FROM_UNIXTIME()函数返回连接当前时区中的值,该值可用作time_zone系统变量的值.此外,UNIX_TIMESTAMP()假定其参数是当前时区中的日期时间值.

当前时区设置不会影响由UTC_TIMESTAMP()等函数或DATE,TIME或DATETIME列中的值显示的值.

注意:如果更改字段,ON UPDATE ONLY仅更新DateTime如果UPDATE导致没有更改字段,则DateTime不会更新!

另外,即使未指定,第一个TIMESTAMP默认也始终为AUTOUPDATE

在使用Dates时,我几乎总是转向Julian Date,因为数据数学是一个简单的加法或减去整数的问题,而Midnight因为同样的原因.我很少需要时间来恢复比秒更精细的粒度.

这两个都可以存储为4字节整数,如果空间非常紧,可以合并到UNIX时间(自1970年1月1日以来的秒数)作为无符号整数,直到2106左右为止:

'秒24小时= 86400

'签名整数最大值= 2,147,483,647 - 可以持有68年的秒数

'无符号整数最大值= 4,294,967,295 - 可以保持136年的秒数

二进制协议:

MySQL 4.1引入了一种二进制协议,允许以原生格式发送和返回非字符串数据值,而无需转换为字符串格式.(非常有用)

另外,mysql_real_query()比mysql_query()更快,因为它不会调用strlen()来操作语句字符串.

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html 二进制协议支持服务器端预处理语句,并允许以本机格式传输数据值.在MySQL 4.1的早期版本中,二进制协议经历了相当多的修订.

您可以使用IS_NUM()宏来测试字段是否具有数字类型.将类型值传递给IS_NUM(),如果字段为数字,则计算结果为TRUE:

有一点要注意的是,二进制数据CAN常规查询中被发送,如果你逃避它,记住MySQL的要求是反斜线和引号字符转义.因此,这是一种非常简单的方法来插入较短的二进制字符串,例如加密/ Salted密码.

主服务器:

http://www.experts-exchange.com/Database/MySQL/Q_22967482.html

http://www.databasejournal.com/features/mysql/article.php/10897_3355201_2

授予复制权限.to slave_user由'slave_password'识别

#Master Binary Logging Config  STATEMENT causes replication 
              to be statement-based -  default

log-bin=Mike
binlog-format=STATEMENT
server-id=1            
max_binlog_size = 10M
expire_logs_days = 120    


#Slave Config
master-host=master-hostname
master-user=slave-user
master-password=slave-password
server-id=2
Run Code Online (Sandbox Code Playgroud)

二进制日志文件必须为:

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://www.mydigitallife.info/2007/10/06/how-to-read-mysql-binary-log-files-binlog-with-mysqlbinlog/

http://dev.mysql.com/doc/refman/5.1/en/mysqlbinlog.html

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://dev.mysql.com/doc/refman/5.1/en/binary-log-setting.html

您可以使用RESET MASTER语句删除所有二进制日志文件,或使用PURGE MASTER删除它们的子集

--result-file = binlog.txt TrustedFriend-bin.000030

正常化:

http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html

UDF功能

http://www.koders.com/cpp/fid10666379322B54AD41AEB0E4100D87C8CDDF1D8C.aspx

http://souptonuts.sourceforge.net/readme_mysql.htm

数据类型:

http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

http://www.informit.com/articles/article.aspx?p=1238838&seqNum=2

http://bitfilm.net/2008/03/24/saving-bytes-efficient-data-storage-mysql-part-1/

需要注意的一点是,在包含CHAR和VARCHAR的混合表中,mySQL会将CHAR更改为VARCHAR的

RecNum integer_type UNSIGNED NOT NULL AUTO_INCREMENT,PRIMARY KEY(RecNum)

根据标准的SQL和ISO 8601规范,MySQL始终首先表示年份的日期

其他:

关闭一些MySQl功能将导致更小的数据文件和更快的访问.例如:

--datadir将指定数据目录和

--skip-innodb将关闭inno选项并为您节省10-20M

更多信息,请访问 http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

下载第7章 - 免费

InnoDB是事务性的,但它带来了性能开销.我发现MyISAM表足以满足90%的项目需求.非事务安全表(MyISAM)有自己的几个优点,所有这些都是因为:

没有交易开销:

快多了

降低磁盘空间要求

执行更新所需的内存更少

每个MyISAM表都以三个文件存储在磁盘上.这些文件的名称以表名开头,并具有指示文件类型的扩展名..frm文件存储表格式.数据文件具有.MYD(MYData)扩展名.索引文件具有.MYI(MYIndex)扩展名.

这些文件可以完整地复制到存储位置,而不使用耗时的MySQL管理员备份功能(恢复时也是如此)

诀窍是制作这些文件的副本然后DROP表.当您放回文件时,MySQl将识别它们并更新表跟踪.

如果必须备份/还原,

恢复备份或从现有转储文件导入可能需要很长时间,具体取决于每个表上的索引和主键的数量.您可以通过使用以下内容修改原始转储文件来显着加快此过程:

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;
Run Code Online (Sandbox Code Playgroud)

要大幅提高重载速度,请添加SQL命令SET AUTOCOMMIT = 0; 在转储文件的开头,添加COMMIT; 命令到最后.

默认情况下,自动提交已启用,这意味着转储文件中的每个插入命令都将被视为单独的事务,并在下一个启动之前写入磁盘.如果您不添加这些命令,将大型数据库重新加载到InnoDB可能需要很长时间......

MySQL表中行的最大大小为65,535字节

MySQL 5.0.3中的VARCHAR的有效最大长度以及=最大行大小(65,535字节)

存储VARCHAR值时不会填充它们.根据标准SQL,在存储和检索值时保留尾随空格.

比较MySQL中的CHAR和VARCHAR值而不考虑尾随空格.

如果整个记录的大小固定,使用CHAR只会加快访问速度.也就是说,如果您使用任何可变大小的对象,您也可以使它们全部变量大小.通过在包含VARCHAR的表中使用CHAR,您无法获得速度.

从MySQL 5.0.3开始,将255个字符的VARCHAR限制提升到65535个字符

仅MyISAM表支持全文搜索.

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

BLOB列没有字符集,排序和比较基于列值中字节的数值

如果未启用严格SQL模式,并且您为BLOB或TEXT列分配的值超出了列的最大长度,则会截断该值以使其适合并生成警告.

有用的命令:

检查严格模式:SELECT @@ global.sql_mode;

关闭严格模式:

SET @@ global.sql_mode ='';

SET @@ global.sql_mode ='MYSQL40'

或删除:sql-mode ="STRICT_TRANS_TABLES,...

显示列 mytable

SELECT max(namecount)AS virtualcolumnFROM mytable ORDER BY virtualcolumn

http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-fields.html

http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_last-insert-id last_insert_id()

获取当前线程中插入的最后一行的PK(pkcolname)获取最后一次PK总体.

注意:如果表为空,则max(pkcolname)返回1 mysql_insert_id()将本机MySQL C API函数mysql_insert_id()的返回类型转换为long类型(在PHP中命名为int).

如果您的AUTO_INCREMENT列的列类型为BIGINT,则mysql_insert_id()返回的值将不正确.而是在SQL查询中使用内部MySQL SQL函数LAST_INSERT_ID().

http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id

请注意,当您尝试将数据插入表中时,您会收到错误消息:

Unknown column ‘the first bit of data what you want to put into the table‘ in ‘field list’
Run Code Online (Sandbox Code Playgroud)

使用类似的东西

INSERT INTO table (this, that) VALUES ($this, $that)
Run Code Online (Sandbox Code Playgroud)

这是因为你没有得到任何撇号,你试图坚持到表中.因此,您应该将代码更改为:

INSERT INTO table (this, that) VALUES ('$this', '$that') 
Run Code Online (Sandbox Code Playgroud)

提醒一下``用于定义MySQL字段,数据库或表,而不是值;)

查询期间与服务器的连接丢失:

http://dev.mysql.com/doc/refman/5.1/en/gone-away.html

http://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html

http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html

http://dev.mysql.com/doc/refman/5.1/en/show-variables.html

http://dev.mysql.com/doc/refman/5.1/en/option-files.html

http://dev.mysql.com/doc/refman/5.1/en/error-log.html

调整查询

http://www.artfulsoftware.com/infotree/queries.php?&bw=1313

那应该足以赚取我想的奖金......许多小时的成果和很多项目都有很棒的免费数据库.我主要使用MySQL在Windows平台上开发应用程序数据服务器.我不得不理顺的最糟糕的事情是

最终MySQL遗留数据库的噩梦

这需要一系列的应用程序,使用这里提到的许多技巧将表格处理成有用的东西.

如果您发现这非常有用,请通过投票表达您的感谢.

另请查看我的其他文章和白皮书:www.coastrd.com


mat*_*mat 22

其中的MySQL并不是那么隐藏的功能是,它不是在为SQL兼容的真的很好,很好,不是真正的错误,但是,更多的陷阱 ... :-)

  • 与许多其他数据库相比,MySQL在SQL兼容方面并不是特别糟糕; 只要你坚持一个理智的SQL子集,你通常可以避免陷阱 - 这可以说是例如.Oracle臭名昭着的NULL空字符串. (3认同)

Era*_*rin 21

用于查找缓存中当前哪些表的命令:

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

(来自MySQL性能博客)


CMS*_*CMS 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) 
Run Code Online (Sandbox Code Playgroud)

你可以用以下方法杀死进程:

mysql>kill 5 
Run Code Online (Sandbox Code Playgroud)

  • 如果您不希望截断查询,也显示完整的PROCESSLIST. (5认同)

Aln*_*tak 11

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

  • PostgreSQL有一个非常好的inet类型,它非常好地处理ipv4和ipv6 :-) (2认同)

Kor*_*nel 11

我爱on duplicate key(AKA upsert,merge)适用于懒惰创建的各种计数器:

insert into occurances(word,count) values('foo',1),('bar',1) 
  on duplicate key cnt=cnt+1
Run Code Online (Sandbox Code Playgroud)

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


小智 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
Run Code Online (Sandbox Code Playgroud)

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

例1:简单

SELECT   CountryCode
,        GROUP_CONCAT(Language) AS List
FROM     CountryLanguage
GROUP BY CountryCode             
Run Code Online (Sandbox Code Playgroud)

输出:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | Dutch,English,Papiamento,Spanish   |
. ...         . ...                                .
| ZWE         | English,Ndebele,Nyanja,Shona       |
+-------------+------------------------------------+
Run Code Online (Sandbox Code Playgroud)

示例2:多个参数

SELECT   CountryCode
,        GROUP_CONCAT(
             Language
,            IF(IsOfficial='T', ' (Official)', '')
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode
Run Code Online (Sandbox Code Playgroud)

输出:

+-------------+---------------------------------------------+
| CountryCode | List                                        |
+-------------+---------------------------------------------+
| ABW         | Dutch (Official),English,Papiamento,Spanish |
. ...         . ...                                         .
| ZWE         | English (Official),Ndebele,Nyanja,Shona     |
+-------------+---------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

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

SELECT   CountryCode
,        GROUP_CONCAT(Language SEPARATOR ' and ') AS List
FROM     CountryLanguage
GROUP BY CountryCode
Run Code Online (Sandbox Code Playgroud)

输出:

+-------------+----------------------------------------------+
| CountryCode | List                                         |
+-------------+----------------------------------------------+
| ABW         | Dutch and English and Papiamento and Spanish |
. ...         . ...                                          .
| ZWE         | English and Ndebele and Nyanja and Shona     |
+-------------+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

示例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
Run Code Online (Sandbox Code Playgroud)

输出:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | English,Papiamento,Spanish,Dutch,  |
. ...         . ...                                .
| ZWE         | Ndebele,Nyanja,Shona,English       |
+-------------+------------------------------------+
Run Code Online (Sandbox Code Playgroud)

功能:COUNT(DISTINCT)具有多个表达式

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

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

Feature/Gotcha:无需在GROUP BY列表中包含非聚合表达式

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

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

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

GROUP BY   Country.Code, Country.Continent
Run Code Online (Sandbox Code Playgroud)

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

SELECT     Country.Code, MAX(Country.Continent), COUNT(CountryLanguage.Language)
Run Code Online (Sandbox Code Playgroud)

现在,问题是,从逻辑上讲,没有任何东西要求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
Run Code Online (Sandbox Code Playgroud)

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

请参阅:神话中的揭穿小组


Mar*_*rkR 7

客户端中的"pager"命令

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

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;
Run Code Online (Sandbox Code Playgroud)

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

pager tee myfile.txt
select a_few_things FROM tbl WHERE i_want_to_save_output_to_a_file;
Run Code Online (Sandbox Code Playgroud)

将方便地写入文件.


Sor*_*inV 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
Run Code Online (Sandbox Code Playgroud)