我已经使用Microsoft SQL Server已有很多年了,但是直到最近才开始在我的Web应用程序中使用MySQL,并且我渴望获得知识。
为了继续解决“隐藏功能”问题,我想知道MySQL的任何隐藏或方便功能,这些功能有望改善我对这个开源数据库的了解。
我已经使用Microsoft SQL Server已有很多年了,但是直到最近才开始在我的Web应用程序中使用MySQL,并且我渴望获得知识。
为了继续解决“隐藏功能”问题,我想知道MySQL的任何隐藏或方便功能,这些功能有望改善我对这个开源数据库的了解。
Answers:
既然您悬赏,我将分享我的来之不易的秘密...
通常,我今天调整的所有SQL都需要使用子查询。来自Oracle数据库世界后,我认为理所当然的事情与MySQL并不一致。我对MySQL调优的阅读使我得出结论,就优化查询而言,MySQL落后于Oracle。
尽管大多数B2C应用程序所需的简单查询在MySQL上可能会很好地运行,但是Intelligence Reporting所需的大多数汇总报告查询类型似乎都需要进行大量规划和重新组织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;
或SET INSERT_ID =值;
除非另有说明,否则该值将以: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()
如果您在MySQL
中将日期时间转换为Unix时间戳:然后对其添加24小时:
然后将其转换回其神奇地浪费了一个小时的日期时间!
这是正在发生的事情。将unix时间戳转换回日期时间时,会考虑时区,并且恰好发生在2006年10月28日至29日之间,我们不使用夏令时并浪费了一个小时。
从MySQL 4.1.3开始,CURRENT_TIMESTAMP(),CURRENT_TIME(),CURRENT_DATE()和FROM_UNIXTIME()函数在连接的当前时区中返回值,这些值可用作time_zone系统变量的值。另外,UNIX_TIMESTAMP()假定其参数是当前时区中的datetime值。
当前时区设置不会影响由UTC_TIMESTAMP()之类的函数显示的值或DATE,TIME或DATETIME列中的值。
注意:ON UPDATE 仅在更改字段时才更新DateTime如果UPDATE导致没有字段被更改,则DateTime不会更新!
另外,即使未指定,默认情况下,“第一时间”始终始终为AUTOUPDATE
使用日期时,我几乎总是迷恋朱利安日期,因为出于同样的原因,数据数学是一个简单的问题,就是添加或减去整数,以及自午夜以来的秒数。我很少需要比秒更细粒度的时间设定。
这两个都可以存储为4个字节的整数,并且如果空间确实很紧凑,则可以将其合并为UNIX时间(自1970年1月1日以来的秒数),作为无符号整数,直到2106年左右为止,它都是有效的:
24小时的秒数= 86400
'有符号整数的最大val = 2,147,483,647-可以保持68年的秒数
'Unsigned Integer max val = 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的要求仅是反斜线和引号字符转义。因此,这是插入较短的二进制字符串(例如,加密/盐密码)的简单方法。
http://www.experts-exchange.com/Database/MySQL/Q_22967482.html
http://www.databasejournal.com/features/mysql/article.php/10897_3355201_2
授予复制奴隶。对slave_user IDENTIFIED BY'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
二进制日志文件必须读取:
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
http://www.koders.com/cpp/fid10666379322B54AD41AEB0E4100D87C8CDDF1D8C.aspx
http://souptonuts.sourceforge.net/readme_mysql.htm
http://dev.mysql.com/doc/refman/5.1/zh-CN/storage-requirements.html
http://www.informit.com/articles/article.aspx?p=1238838&seqNum=2
http://bitfilm.net/2008/03/24/saving-bytes-efficiency-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 Administrators备份功能(还原也是如此)
技巧是复制这些文件,然后删除表。当您将文件放回MySQl将识别它们并更新表跟踪。
如果您必须备份/还原,
还原备份或从现有转储文件导入可能需要很长时间,具体取决于每个表上的索引数和主键数。通过用以下内容包围原始转储文件,可以大大加快此过程:
SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;
.. your dump file ..
SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;
要大大提高重新加载的速度,请添加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起,VARCHAR限制从255个字符增加到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
virtualcolumn
从mytable ORDER BY virtualcolumn中选择max(namecount)AS
http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-fields.html
http://dev.mysql.com/doc/refman/5.1/zh-CN/information-functions.html#function_last-insert-id last_insert_id()
获取您当前线程中插入的最后一行的PK。max(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/zh-CN/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’
使用类似
INSERT INTO table (this, that) VALUES ($this, $that)
这是因为您想要插入表格中的值周围没有任何撇号。因此,您应该将代码更改为:
INSERT INTO table (this, that) VALUES ('$this', '$that')
提醒您,``用于定义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/zh-CN/error-log.html
http://www.artfulsoftware.com/infotree/queries.php?&bw=1313
好吧,这足以赚到我认为的奖金...很多小时的成果和许多拥有免费数据库的项目。我主要使用MySQL在Windows平台上开发应用程序数据服务器。我要弄得最糟的一件事是
这需要一系列的应用,才能使用这里提到的许多技巧将表处理成有用的东西。
如果您发现这非常有用,请通过投票表示感谢。
还可以在以下位置查看我的其他文章和白皮书:www.coastrd.com
MySQL并非如此隐藏的功能之一是,它实际上并不擅长于与SQL兼容,嗯,不是真正的bug,而是更多的陷阱 ……:-)
SET SESSION sql_mode='ANSI';
查找高速缓存中当前有哪些表的命令:
mysql> SHOW open TABLES FROM test;
+----------+-------+--------+-------------+
| DATABASE | TABLE | In_use | Name_locked |
+----------+-------+--------+-------------+
| test | a | 3 | 0 |
+----------+-------+--------+-------------+
1 row IN SET (0.00 sec)
(来自MySQL性能博客)
找出谁在做什么的命令:
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
我喜欢on duplicate key
(又名upsert,merge)懒惰创建的各种计数器:
insert into occurances(word,count) values('foo',1),('bar',1)
on duplicate key cnt=cnt+1
您可以在一个查询中插入许多行,并立即为每行处理重复索引。
再说一遍-不是真正的隐藏功能,但非常方便:
特征
轻松获取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都执行符合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
无效,因为SELECT列表包含未汇总的Country.Continent列,该列未出现在GROUP BY列表中。在这些RDBMS-es中,您必须修改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列将包含无意义的内容(也就是说,在所有语言百分比中,该百分比的可用值之一将被随机选择,或者至少会在您的控制范围之内。
参见:揭穿神话
客户端中的“寻呼机”命令
例如,如果您的结果中有10,000行并希望查看它们(这假定可用的“ less”和“ tee”命令,在Windows YMMV中通常是Linux下的情况)。
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;
将方便地写入文件。
这不是隐藏的功能,但仍然有用:http : //mtop.sourceforge.net/
如果您要使用大型和/或高交易量的InnoDb数据库,请学习并理解Mysql Performance Blog的 “ SHOW INNODB STATUS” ,它将成为您的朋友。
如果使用cmdline Mysq,则可以使用shriek /感叹号与命令行交互(在Linux计算机上-不确定Windows是否具有等效效果)。例如:
\! cat file1.sql
将显示file1.sql的代码。要将语句保存并查询到文件,请使用tee工具
\T filename
要关闭此功能,请使用\ t
最后,要运行已保存的脚本,请使用“源文件名”。当然,通常的替代方法是从命令行启动mysql时直接输入脚本名称:
mysql -u root -p < case1.sql
希望对某人有用!
编辑:刚刚想起了另一个-从命令行调用mysql时,您可以使用-t开关,以便输出以表格式显示-带有某些查询的真正好处(尽管当然也终止了\ G的查询,如此处其他地方所述)在这方面很有帮助)。有关各种开关的更多信息命令行工具
刚刚找到了一种巧妙的方法来更改排序顺序(通常使用Case ...)。如果要更改排序顺序(也许按1、4、3、2而不是1、2、3, 4)您可以在Order by子句中使用field函数。例如
按字段排序(sort_field,1,4,3,2)
我不认为这是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)
在具有大型数据集和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'