mysql mysql按多列分组排序序,pid为 n 的行 跟在 id 为 n 的行后面

basedir = path
使用给定目录作为根目录(安装目录)。
character-sets-dir = path
给出存放着字符集的目录。
datadir = path
从给定目录读取数据库文件。
pid-file = filename
为mysqld程序指定一个存放进程ID的文件(仅适用于UNIX/Linux系统);
Init-V脚本需要使用这个文件里的进程ID结束mysqld进程。
socket = filename
为MySQL客户程序与服务器之间的本地通信指定一个套接字文件(仅适用于UNIX/Linux系统;默认设置一般是/var/lib/mysql/mysql.sock文件)。在Windows环境下,如果MySQL客户与服务器是通过命名管道进行通信的,–sock选项给出的将是该命名管道的名字(默认设置是MySQL)。
lower_case_table_name = 1/0
新目录和数据表的名字是否只允许使用小写字母;这个选项在Windows环境下的默认设置是1(只允许使用小写字母)。
mysqld程序:语言设置
character-sets-server = name
新数据库或数据表的默认字符集。为了与MySQL的早期版本保持兼容,这个字符集也可以用–default-character-set选项给出;但这个选项已经显得有点过时了。
collation-server = name
新数据库或数据表的默认排序方式。
lanuage = name
用指定的语言显示出错信息。
mysqld程序:通信、网络、信息安全
enable-named-pipes
允许Windows 2000/XP环境下的客户和服务器使用命名管道(named pipe)进行通信。这个命名管道的默认名字是MySQL,但可以用–socket选项来改变。
local-infile [=0]
允许/禁止使用LOAD DATA LOCAL语句来处理本地文件。
myisam-recover [=opt1, opt2, ...]
在启动时自动修复所有受损的MyISAM数据表。这个选项的可取值有4种:DEFAULT、BACKUP、QUICK和FORCE;它们与myisamchk程序的同名选项作用相同。
old-passwords
使用MySQL 3.23和4.0版本中的老算法来加密mysql数据库里的密码(默认使用MySQL
4.1版本开始引入的新加密算法)。
为MySQL程序指定一个TCP/IP通信端口(通常是3306端口)。
safe-user-create
只有在mysql.user数据库表上拥有INSERT权限的用户才能使用GRANT命令;这是一种双保险机制(此用户还必须具备GRANT权限才能执行GRANT命令)。
shared-memory
允许使用内存(shared memory)进行通信(仅适用于Windows)。
shared-memory-base-name = name
给共享内存块起一个名字(默认的名字是MySQL)。
skip-grant-tables
不使用mysql数据库里的信息来进行访问控制(警告:这将允许用户任何用户去修改任何数据库)。
skip-host-cache
不使用高速缓存区来存放主机名和IP地址的对应关系。
skip-name-resovle
不把IP地址解析为主机名;与访问控制(mysql.user数据表)有关的检查全部通过IP地址行进。
skip-networking
只允许通过一个套接字文件(Unix/Linux系统)或通过命名管道(Windows系统)进行本地连接,不允许ICP/IP连接;这提高了安全性,但阻断了来自网络的外部连接和所有的Java客户程序(Java客户即使在本地连接里也使用TCP/IP)。
user = name
mysqld程序在启动后将在给定UNIX/Linux账户下执行; mysqld必须从root账户启动才能在启动后切换到另一个账户下执行;
mysqld_safe脚本将默认使用–user=mysql选项来启动mysqld程序。
mysqld程序:内存管理、优化、查询缓存区
bulk_insert_buffer_size = n
为一次插入多条新记录的INSERT命令分配的缓存区长度(默认设置是8M)。
key_buffer_size = n
用来存放索引区块的RMA值(默认设置是8M)。
join_buffer_size = n
在参加JOIN操作的数据列没有索引时为JOIN操作分配的缓存区长度(默认设置是128K)。
max_heap_table_size = n
HEAP数据表的最大长度(默认设置是16M);超过这个长度的HEAP数据表将被存入一个临时文件而不是驻留在内存里。
max_connections = n
MySQL服务器同时处理的数据库连接的最大数量(默认设置是100)。
query_cache_limit = n
允许临时存放在查询缓存区里的查询结果的最大长度(默认设置是1M)。
query_cache_size = n
查询缓存区的最大长度(默认设置是0,不开辟查询缓存区)。
query_cache_type = 0/1/2
查询缓存区的工作模式:0,
禁用查询缓存区; 1,启用查询缓存区(默认设置); 2,”按需分配”模式,只响应SELECT
SQL_CACHE命令。
read_buffer_size = n
为从数据表顺序读取数据的读操作保留的缓存区的长度(默认设置是128KB);这个选项的设置值在必要时可以用SQL命令SET
SESSION read_buffer_size = n命令加以改变。
read_rnd_buffer_size = n
类似于read_buffer_size选项,但针对的是按某种特定顺序(比如使用了ORDER BY子句的查询)输出的查询结果(默认设置是256K)。
sore_buffer = n
为排序操作分配的缓存区的长度(默认设置是2M);如果这个缓存区太小,则必须创建一个临时文件来进行排序。
table_cache = n
同时打开的数据表的数量(默认设置是64)。
tmp_table_size = n
临时HEAP数据表的最大长度(默认设置是32M);超过这个长度的临时数据表将被转换为MyISAM数据表并存入一个临时文件。
mysqld程序:日志
log [= file]
把所有的连接以及所有的SQL命令记入日志(通用查询日志);如果没有给出file参数,MySQL将在数据库目录里创建一个hostname.log文件作为这种日志文件(hostname是服务器的主机名)。
log-slow-queries [= file]
把执行用时超过long_query_time变量值的查询命令记入日志(慢查询日志);如果没有给出file参数,MySQL将在数据库目录里创建一个hostname-slow.log文件作为这种日志文件(hostname是服务器主机名)。
long_query_time = n
慢查询的执行用时上限(默认设置是10s)。
long_queries_not_using_indexs
把慢查询以及执行时没有使用索引的查询命令全都记入日志(其余同–log-slow-queries选项)。
log-bin [= filename]
把对数据进行修改的所有SQL命令(也就是INSERT、UPDATE和DELETE命令)以二进制格式记入日志(二进制变更日志,binary
update log)。这种日志的文件名是filename.n或默认的hostname.n,其中n是一个6位数字的整数(日志文件按顺序编号)。
log-bin-index = filename
二进制日志功能的索引文件名。在默认情况下,这个索引文件与二进制日志文件的名字相同,但后缀名是.index而不是.nnnnnn。
max_binlog_size = n
二进制日志文件的最大长度(默认设置是1GB)。在前一个二进制日志文件里的信息量超过这个最大长度之前,MySQL服务器会自动提供一个新的二进制日志文件接续上。
binlog-do-db = dbname
只把给定数据库里的变化情况记入二进制日志文件,其他数据库里的变化情况不记载。如果需要记载多个数据库里的变化情况,就必须在配置文件使用多个本选项来设置,每个数据库一行。
binlog-ignore-db = dbname
不把给定数据库里的变化情况记入二进制日志文件。
sync_binlog = n
每经过n次日志写操作就把日志文件写入硬盘一次(对日志信息进行一次同步)。n=1是最安全的做法,但效率最低。默认设置是n=0,意思是由操作系统来负责二进制日志文件的同步工作。
log-update [= file]
记载出错情况的日志文件名(出错日志)。这种日志功能无法禁用。如果没有给出file参数,MySQL会使用hostname.err作为种日志文件的名字。
mysqld程序:镜像(主控镜像服务器)
server-id = n
给服务器分配一个独一无二的ID编号; n的取值范围是1~2的32次方启用二进制日志功能。
log-bin = name
启用二进制日志功能。这种日志的文件名是filename.n或默认的hostname.n,其中的n是一个6位数字的整数(日志文件顺序编号)。
binlog-do/ignore-db = dbname
只把给定数据库里的变化情况记入二进制日志文件/不把给定的数据库里的变化记入二进制日志文件。
mysqld程序:镜像(从属镜像服务器)
server-id = n
给服务器分配一个唯一的ID编号
log-slave-updates
启用从属服务器上的日志功能,使这台计算机可以用来构成一个镜像链(A-&B-&C)。
master-host = hostname
主控服务器的主机名或IP地址。如果从属服务器上存在mater.info文件(镜像关系定义文件),它将忽略此选项。
master-user = replicusername
从属服务器用来连接主控服务器的用户名。如果从属服务器上存在mater.info文件,它将忽略此选项。
master-password = passwd
从属服务器用来连接主控服务器的密码。如果从属服务器上存在mater.info文件,它将忽略此选项。
master-port = n
从属服务器用来连接主控服务器的TCP/IP端口(默认设置是3306端口)。
master-connect-retry = n
如果与主控服务器的连接没有成功,则等待n秒(s)后再进行管理方式(默认设置是60s)。如果从属服务器存在mater.info文件,它将忽略此选项。
master-ssl-xxx = xxx
对主、从服务器之间的SSL通信进行配置。
read-only = 0/1
0: 允许从属服务器独立地执行SQL命令(默认设置);
1: 从属服务器只能执行来自主控服务器的SQL命令。
read-log-purge = 0/1
1: 把处理完的SQL命令立刻从中继日志文件里删除(默认设置);
0: 不把处理完的SQL命令立刻从中继日志文件里删除。
replicate-do-table = dbname.tablename
与–replicate-do-table选项的含义和用法相同,但数据库和数据库表名字里允许出现通配符”%” (例如:
test%.%–对名字以”test”开头的所有数据库里的所以数据库表进行镜像处理)。
replicate-do-db = name
只对这个数据库进行镜像处理。
replicate-ignore-table = dbname.tablename
不对这个数据表进行镜像处理。
replicate-wild-ignore-table = dbn.tablen
不对这些数据表进行镜像处理。
replicate-ignore-db = dbname
不对这个数据库进行镜像处理。
replicate-rewrite-db = db1name & db2name
把主控数据库上的db1name数据库镜像处理为从属服务器上的db2name数据库。
report-host = hostname
从属服务器的主机名;
这项信息只与SHOW SLAVE HOSTS命令有关–主控服务器可以用这条命令生成一份从属服务器的名单。
slave-compressed-protocol = 1
主、从服务器使用压缩格式进行通信–如果它们都支持这么做的话。
slave-skip-errors = n1, n2, …或all
即使发生出错代码为n1、n2等的错误,镜像处理工作也继续进行(即不管发生什么错误,镜像处理工作也继续进行)。如果配置得当,从属服务器不应该在执行
SQL命令时发生错误(在主控服务器上执行出错的SQL命令不会被发送到从属服务器上做镜像处理);如果不使用slave-skip-errors选项,从属服务器上的镜像工作就可能因为发生错误而中断,中断后需要有人工参与才能继续进行。
mysqld–InnoDB:基本设置、表空间文件
skip-innodb
不加载InnoDB数据表驱动程序–如果用不着InnoDB数据表,可以用这个选项节省一些内存。
innodb-file-per-table
为每一个新数据表创建一个表空间文件而不是把数据表都集中保存在中央表空间里(后者是默认设置)。该选项始见于MySQL
innodb-open-file = n
InnoDB数据表驱动程序最多可以同时打开的文件数(默认设置是300)。如果使用了innodb-file-per-table选项并且需要同时打开很多数据表的话,这个数字很可能需要加大。
innodb_data_home_dir = p
InnoDB主目录,所有与InnoDB数据表有关的目录或文件路径都相对于这个路径。在默认的情况下,这个主目录就是MySQL的数据目录。
innodb_data_file_path = ts
用来容纳InnoDB为数据表的表空间:可能涉及一个以上的文件;每一个表空间文件的最大长度都必须以字节(B)、兆字节(MB)或千兆字节(GB)为单位给出;表空间文件的名字必须以分号隔开;最后一个表空间文件还可以带一个autoextend属性和一个最大长度(max:n)。例如,ibdata1:1G;
ibdata2:1G:autoextend:max:2G的意思是:表空间文件ibdata1的最大长度是1GB,ibdata2的最大长度也是1G,但允许它扩充到2GB。除文件名外,还可以用硬盘分区的设置名来定义表空间,此时必须给表空间的最大初始长度值加上newraw关键字做后缀,给表空间的最大扩充长度值加上raw关键字做后缀(例如/dev/hdb1:
20Gnewraw或/dev/hdb1:20Graw); MySQL 4.0及更高版本的默认设置是ibdata1:10M:autoextend。
innodb_autoextend_increment = n
带有autoextend属性的表空间文件每次加大多少兆字节(默认设置是8MB)。这个属性不涉及具体的数据表文件,那些文件的增大速度相对是比较小的。
innodb_lock_wait_timeout = n
如果某个事务在等待n秒(s)后还没有获得所需要的资源,就使用ROLLBACK命令放弃这个事务。这项设置对于发现和处理未能被InnoDB数据表驱动程序识别出来的死锁条件有着重要的意义。这个选项的默认设置是50s。
innodb_fast_shutdown 0/1
是否以最快的速度关闭InnoDB,默认设置是1,意思是不把缓存在INSERT缓存区的数据写入数据表,那些数据将在MySQL服务器下次启动时再写入
(这么做没有什么风险,因为INSERT缓存区是表空间的一个组成部分,数据不会丢失)。把这个选项设置为0反面危险,因为在计算机关闭时,InnoDB驱动程序很可能没有足够的时间完成它的数据同步工作,操作系统也许会在它完成数据同步工作之前强行结束InnoDB,而这会导致数据不完整。
mysqld程序:InnoDB–日志
innodb_log_group_home_dir = p
用来存放InnoDB日志文件的目录路径(如ib_logfile0、ib_logfile1等)。在默认的情况下,InnoDB驱动程序将使用
MySQL数据目录作为自己保存日志文件的位置。
innodb_log_files_in_group = n
使用多少个日志文件(默认设置是2)。InnoDB数据表驱动程序将以轮转方式依次填写这些文件;当所有的日志文件都写满以后,之后的日志信息将写入第一个日志文件的最大长度(默认设置是5MB)。这个长度必须以MB(兆字节)或GB(千兆字节)为单位进行设置。
innodb_flush_log_at_trx_commit = 0/1/2
这个选项决定着什么时候把日志信息写入日志文件以及什么时候把这些文件物理地写(术语称为”同步”)到硬盘上。设置值0的意思是每隔一秒写一次日志并进行同步,这可以减少硬盘写操作次数,但可能造成数据丢失;设置值1(设置设置)的意思是在每执行完一条COMMIT命令就写一次日志并进行同步,这可以防止数据丢失,但硬盘写操作可能会很频繁;设置值2是一般折衷的办法,即每执行完一条COMMIT命令写一次日志,每隔一秒进行一次同步。
innodb_flush_method = x
InnoDB日志文件的同步办法(仅适用于UNIX/Linux系统)。这个选项的可取值有两种:
fdatasync,用fsync()函数进行同步; O_DSYNC,用O_SYNC()函数进行同步。
innodb_log_archive = 1
启用InnoDB驱动程序的archive(档案)日志功能,把日志信息写入ib_arch_log_n文件。启用这种日志功能在InnoDB与
MySQL一起使用时没有多大意义(启用MySQL服务器的二进制日志功能就足够用了)。
mysqld程序–InnoDB:缓存区的设置和优化
innodb_log_buffer_pool_size = n
为InnoDB数据表及其索引而保留的RAM内存量(默认设置是8MB)。这个参数对速度有着相当大的影响,如果计算机上只运行有
MySQL/InnoDB数据库服务器,就应该把全部内存的80%用于这个用途。
innodb_log_buffer_size = n
事务日志文件写操作缓存区的最大长度(默认设置是1MB)。
innodb_additional_men_pool_size = n
为用于内部管理的各种数据结构分配的缓存区最大长度(默认设置是1MB)。
innodb_file_io_threads = n
I/O操作(硬盘写操作)的最大线程个数(默认设置是4)。
innodb_thread_concurrency = n
InnoDB驱动程序能够同时使用的最大线程个数(默认设置是8)。
mysqld程序:其它选项
bind-address = ipaddr
MySQL服务器的IP地址。如果MySQL服务器所在的计算机有多个IP地址,这个选项将非常重要。
default-storage-engine = type
新数据表的默认数据表类型(默认设置是MyISAM)。这项设置还可以通过–default-table-type选项来设置。
default-timezone = name
为MySQL服务器设置一个地理时区(如果它与本地计算机的地理时区不一样)。
ft_min_word_len = n
全文索引的最小单词长度工。这个选项的默认设置是4,意思是在创建全文索引时不考虑那些由3个或更少的字符构建单词。
Max-allowed-packet = n
客户与服务器之间交换的数据包的最大长度,这个数字至少应该大于客户程序将要处理的最大BLOB块的长度。这个选项的默认设置是1MB。
Sql-mode = model1, mode2, …
MySQL将运行在哪一种SQL模式下。这个选项的作用是让MySQL与其他的数据库系统保持最大程度的兼容。这个选项的可取值包括ansi、db2、
oracle、no_zero_date、pipes_as_concat。
linux下自己创建/etc/my.cnf文件导致启动mysql时报错:
Mac OS X下,MySQL在/etc/下没有my.cnf(MySQL修改编码时发现的问题)
mysql在linux下的my.cnf文件在哪里!
mysql启动时,提示/etc/my.cnf 被忽略的问题处理
Linux下my.ini/my.cnf文件路径
mysql启动参数(/etc/my.cnf)详解汇总
没有更多推荐了,解决一个 MySQL 服务器进程 CPU 占用 100%解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记》[转] - clq - 博客园
解决一个 MySQL 服务器进程 CPU 占用 100%解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记》
作者:liyihongcug
转载地址:http://bbs.chinaunix.net/archiver/tid-1823500.html
解决一个 MySQL 服务器进程 CPU 占用 100%解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记》( [url]http://www.xiaohui.com/weekly/.htm[/url] ),谈到自己在解决一个拥有 60 万条记录的 MySQL 数据库访问时,导致 MySQL CPU 占用 100% 的经过。在解决问题完成优化(optimize)之后,我发现 Discuz 论坛也存在这个问题,当时稍微提了一下:
[url]http://www.xiaohui.com/dev/server/-discuz-mysql-cpu-100-optimize.htm[/url] 发现此主机运行了几个 Discuz 的论坛程序, Discuz论坛的好几个表也存在着这个问题。于是顺手一并解决,cpu占用再次降下来了。   前几天,一位朋友通过这篇文章找到了我,说他就是运行最新的 discuz 版本,MySQL 占用 CPU 100%,导致系统假死,每天都要重启好几次,花了一个多月的时间一直没有解决,希望我帮忙一下。经过检查,他的这个论坛最重要的几个表中,目前 cdb_members 表,有记录 6.2 万;cdb_threads 表,有记录 11万;cdb_posts表,有记录 1740 万;所有数据表的记录加起来,超过 2000 万;数据库的大小超过 1GB。经过半天的调试,总算完成了 discuz 论坛优化,于是将其解决经过记录在这篇文章 [url]http://www.xiaohui.com/dev/server/-discuz-mysql-cpu-100-optimize.htm[/url] 中。   2007年3月我发现 discuz 论坛的数据库结构设计有一些疏忽,有许多查询子句的条件比较,都没有建立 Index 索引。当时我所检查的那个数据表,记录只有几千条,因此对 CPU 负荷不大。现在这个数据库表,上千万的记录检索,可以想象,如果数据表结构设计不规范,没有提供索引,所耗费的时间是一个恐怖的数字。有关 MySQL 建立索引的重要性,可以参见我的这篇文章底部的说明:[url]http://www.xiaohui.com/weekly /.htm[/url]   为了调试方便,我从 dizcus 的官网下载了其最新的 Dizcus! 5.5.0 论坛程序.   我首先检查了 my.ini 的参数配置,一切正常。进入 MySQL 的命令行,调用 show processlist 语句,查找负荷最重的 SQL 语句,结合 Discuz 论坛的源码,发现有以下语句导致 CPU 上升:
mysql& +-----+------+----------------+---------+---------+------+------------+--------- -----------------------------------------------------------------+ | Id&&| User | Host& && && &&&| db& && &| Command | Time | State& && &| Info & && && && && && && && && && && && && && && && && && && && && &&&| +-----+------+----------------+---------+---------+------+------------+--------- -----------------------------------------------------------------+ | 363 | root | localhost:1393 | history | Query& &|& & 0 | statistics | SELECT C OUNT(*) FROM cdb_pms WHERE msgfromid=11212 AND folder='outbox' | +-----+------+----------------+---------+---------+------+------------+---------   检查 cdb_pms 表的结构:
mysql& show columns from cdb_ +-----------+------------------------+------+-----+---------+----------------+ | Field& &&&| Type& && && && && && & | Null | Key | Default | Extra& && && & | +-----------+------------------------+------+-----+---------+----------------+ | pmid& && &| int(10) unsigned& && & | NO& &| PRI | NULL& & | auto_increment | | msgfrom& &| varchar(15)& && && && &| NO& &|& &&&|& && && &|& && && && && & | | msgfromid | mediumint(8) unsigned&&| NO& &| MUL | 0& && & |& && && && && & | | msgtoid& &| mediumint(8) unsigned&&| NO& &| MUL | 0& && & |& && && && && & | | folder& & | enum('inbox','outbox') | NO& &|& &&&| inbox& &|& && && && && & | | new& && & | tinyint(1)& && && && & | NO& &|& &&&| 0& && & |& && && && && & | | subject& &| varchar(75)& && && && &| NO& &|& &&&|& && && &|& && && && && & | | dateline&&| int(10) unsigned& && & | NO& &|& &&&| 0& && & |& && && && && & | | message& &| text& && && && && && & | NO& &|& &&&|& && && &|& && && && && & | | delstatus | tinyint(1) unsigned& & | NO& &|& &&&| 0& && & |& && && && && & | +-----------+------------------------+------+-----+---------+----------------+ 10 rows in set (0.00 sec)   这条语句: WHERE msgfromid=11212 AND folder='outbox',我们看到,在 cdb_pms 表中,msgfromid 字段已经建立了索引,但是,folder 字段并没有。目前这个表已经有记录 7823 条。显然,这会对查询造成一定影响。于是为其建立索引:
mysql& ALTER TABLE `cdb_pms` ADD INDEX ( `folder` ); Query OK, 7823 rows affected (1.05 sec) Records: 7823&&Duplicates: 0&&Warnings: 0   继续检查:
mysql& +------+------+----------------+---------+---------+------+------------+-------- -------------------------------------------------------------------------------- --------------+ | Id& &| User | Host& && && &&&| db& && &| Command | Time | State& && &| Info & && && && &&&| +------+------+----------------+---------+---------+------+------------+-------- -------------------------------------------------------------------------------- --------------+ & && && && &&&| | 1583 | root | localhost:2616 | history | Query& &|& & 0 | statistics | SELECT t.tid, t.closed, f.*, ff.*&&, f.fid AS fid & && && && && && && && &FROM cdb_threads t & && && && && && && && &INNER JOIN cdb_forums f | +------+------+----------------+---------+---------+------+------------+-------- -------------------------------------------------------------------------------- --------------+ 1 rows in set (0.00 sec)   这条 SQL 语句是针对最重要的数据表 cdb_threads 进行操作的,由于 show processlist 没有将这条 SQL 语句全部显示完全,经对比 Discuz 论坛的源码,此SQL语句的原型位于 common.inc.php 的 Line 283,内容如下:
$query = $db-&query("SELECT t.tid, t.closed,".(defined('SQL_ADD_THREAD') ? & & SQL_ADD_THREAD : '')." f.*, ff.* $accessadd1 $modadd1, f.fid AS fid & & FROM {$tablepre}threads t & & INNER JOIN {$tablepre}forums f ON f.fid=t.fid & & LEFT JOIN {$tablepre}forumfields ff ON ff.fid=f.fid $accessadd2 $modadd2 & & WHERE t.tid='$tid'".($auditstatuson ? '' : " AND t.displayorder&=0")." LIMIT 1");   经检查,数据表 cdb_threads, 并没有针对 displayorder 字段建立索引。在 discuz 论坛中,displayorder字段多次参与了 Where 子句的比较。于是为其建立索引:
mysql& ALTER TABLE `cdb_threads` ADD INDEX ( `displayorder` ); Query OK, 110330 rows affected (2.36 sec) Records: 110330&&Duplicates: 0&&Warnings: 0   此时 cpu 已经轻微下降了一部分。   继续检查,发现 下面这条 discuz 的 SQL 语句,也导致负荷增加,这条语句位于 rss.php 程序中的第 142 行。
& & $query = $db-&query("SELECT t.tid, t.readperm, t.price, t.author, t.dateline, t.subject, p.message & & FROM {$tablepre}threads t & & LEFT JOIN {$tablepre}posts p ON p.tid=t.tid AND p.first=1 & & WHERE t.fid='$fid' AND t.displayorder&=0 & & ORDER BY t.dateline DESC LIMIT $num");   在这个 Order by 子句中,用到了 cdb_threads 表中的 dataline 字段。这个字段是用来存储 unixtime 的时间戳,在整个论坛程序中,大部分时候数据的排序也是基于这个字段,竟然没有建立索引。于是加上:
mysql& ALTER TABLE `cdb_threads` ADD INDEX ( `dateline` ); Query OK, 110330 rows affected (12.27 sec) Records: 110330&&Duplicates: 0&&Warnings: 0   查找占用 CPU 高负茶的 SQL 语句,是一件麻烦而又枯燥的事,需要一条一条排除、分析。后面的工作,都是依此类推,经过检查,共查出有八处地方,需要增加索引,如果你也碰到了 discuz 5.5.0 论坛导致 cpu 占用 100% 的情况,可以直接将下列语句复制过去,在 mysql 的命令行下执行即可:
ALTER TABLE `cdb_pms` ADD INDEX ( `folder` ); ALTER TABLE `cdb_threads` ADD INDEX ( `displayorder` ); ALTER TABLE `cdb_threads` ADD INDEX ( `dateline` ); ALTER TABLE `cdb_threads` ADD INDEX ( `closed` ); ALTER TABLE `cdb_threadsmod` ADD INDEX ( `dateline` ); ALTER TABLE `cdb_sessions` ADD INDEX ( `invisible` ); ALTER TABLE `cdb_forums` ADD INDEX ( `type` ); ALTER TABLE `cdb_forums` ADD INDEX ( `displayorder` );   注意:&cdb_& 是 discuz 论坛的默认数据表前缀。如果你的表名前缀不是 &cdb_&,则应该改成你对应的表名。例如:my_threads, my_pms 等等。   完成这些结构的优化之后,整个系统的 CPU 负荷在 10%~20%左右震荡,问题解决。   我很奇怪,设计数据库结构,是一个数据库开发人员的基本功,discuz 论坛好歹也是一个发展了有六七年的论坛了,为何数据库结构设计得如此糟糕?我想也许有如下三个原因: 数据库开发人员设计时本身的疏忽
故意留下的缺陷,当普通论坛没有上数量级的记录时,不会感觉到这个问题,当数据量增大(例如千万级),此问题突现,以便针对用户提供个**收取服务费.呵呵,估且以最大的恶意来猜测此事,玩笑而已,不必当真。:) 
另一个可能就是用户的论坛是从低版本升级而来,程序升了级,但数据结构也许没有做相应的更新
附1: 补充笔记
  今天查看网站日志的 reffer, 发现在 discuz 的官方论坛上,有人就此文引起了一些争论: [url]http://www.discuz.net/thread--1.html[/url]。discuz 的管理员和管理员有如下言论:
引用自 cnteacher: 恰恰相反,discuz 的优化措施和数据库的索引是按照大规模论坛设计的。
TO 一楼:数据库结构的设计都是按照程序应用来进行的,使用任何非Discuz! 标准版本以外的代码和程序,或者变更标准数据结构,均可能遇到不可预知的各种问题。
引用自 童虎:
你们可以看看xxxxx, xxxx之类的比较大型的网站,这种网站使用dz论坛都没有问题,说明dz标准程序是没有问题,出现楼主说的情况,多半属于服务器或者安装一些插件造成的
  显然将问题推给插件的原因是不正确的.举个简单的例子:在最新的 discuz 5.5.0 forumdisplay.php 第183 行,有如下语句:
$query = $db-&query("SELECT uid, groupid, username, invisible, &&lastactivity, action FROM {$tablepre}sessions
&&WHERE $guestwhere fid='$fid' AND invisible=0");   这里的 invisible 并没有建立索引。本文中有评论认为 session 表是内存表, 速度会很快。理论是如此。不过我在 show processlist 中,观察到上面这条语句占用了大量 CPU, 所以也将其一并加上了 index。cdb_threads 中的 closed 等字段, 也多次参与 where 运算, 也没有建立索引。这些运算的语句, 是 discuz 自己的程序中的。
附2: 补充笔记
  自从这篇笔记发表以来,在我的这篇文章的评论、以及我的联系消息中,就经常收到许多下面两种类型的评论和邮件:一、许多技术人员批评我胡说八道、 Dizcus 论坛不需要做优化或者不能乱建索引的;二、许多使用Dizcus 的站长找我&冰天雪地裸体跪求&解决他们的 CPU 占用 100% 的问题。   一、关于 MySQL 数据库优化技术上的争论,我的观点再次声明如下: 技术上的争论是可以放开了讨论的。而我的水平也确实只是半瓶水,对数据库的理论知识也只懂这么点,牛牛们的批评,我虚心接心,非常感谢。但是,评论里的批评不要上升到人身攻击,否则,我的地盘我作主,直接删除。
数据库的优化,要涉及到的方方面面很多。关说理论是没有用的,得靠事实说话。一个千万级数据库的实例优化说明不了问题,两个千万级的数据库优化也许还说明 不了问题,但我相信,三个、四个、五个总是可以说明问题的,--截止到 ,我已经帮助朋友优化过五个记录数超过 1000 万的 discuz 论坛了。我想事实胜于雄辩:优化之前,cpu 都是 100%;优化之后,cpu 降到 30%~40% 左右。没错,做 ADD INDEX 会增加数据库 INSERT/UPDATE 时的开销,但别忘了论坛最主要的操作,是 SELECT 查询。
  二、关于找我帮忙解决数据库优化的评论和邮件,答复如下:
数据库的优化,不同的版本有不同的实际情况,优化一个 database,短则三两小时,慢则半天一天。请大家理解这个中年老男人养家的压力,我的精力有限,不可能一一帮到。
对于没有收入的个人网站,我可以在周六周日的空余时间内帮忙。请事先与我联系好。
对于有收入的网站,嗯嗯,自觉点,请带价格与我联系,或者直接安排美女请我吃饭,否则免谈。:) 请不要来信问&优化我们这个论坛你要多少费用?&这样没营养的话,而是直接说&帮我们优化 XXXX 论坛, XXXX RMB 可以不?&,我觉得合适就做。大家都很忙,我的时间很值钱,你要我自己报价,我怕吓着你。
请通过 [url]http://www.xiaohui.com/support/[/url] 与我联系。不要在评论里留个 QQ 号然后要我加你,我不会时时盯着评论看。
附3: 补充笔记 : 关于装有首页四格插件的 dz 论坛导致 MySQL 占用 大量CPU 的分析   今天手机巴士的站长( [url]http://bbs.sj84.com[/url] )找到我,他的基于 Discuz 的论坛,也存在 CPU 占用 100% 的问题,服务器从 Win 2003 换到 CentOS,内存 2G, CPU 1.86G, 数据:cdb_threads 4 万,cdb_posts 96 万,cdb_members 35 万,已经按我上面文章所说的优化过索引。按说这个配置足够运行论坛了,但问题一直得不到解决。   经过调试,将慢查询的结果 dump 到 /usr/local/mysql/var/localhost-slow.log,运行 /usr/local/mysql/bin/mysqldumpslow /usr/local/mysql/var/localhost-slow.log 查看,结合 show processlist 命令,发现慢查询集中在下列语句:
SELECT t.*, f.name FROM cdb_threads t, cdb_forums f WHERE
t.fid&&'S'
AND f.fid=t.fid
AND f.fid NOT IN (N,N,N,N)
AND t.closed NOT LIKE 'S'
AND t.replies !=N
AND t.displayorder&=N
ORDER BY t.views DESC LIMIT N, N   然而搜索 Dizcus 论坛的源码,并没有找到这行代码。怀疑是插件的原因。经查,论坛装了首页四格的插件,这行语句位于 include/toplist.php 中: 仔细检查这行代码,发现存在许多性能或语法规范上的问题: AND t.closed NOT LIKE 'S':t.closed 是数值字段,不应该用 LIKE 'S' 的形式参与比较。 
ORDER BY t.views: t.views 在 dizcus 的原始数据表中,是没有做索引的。
SELECT t.*: 这种写法,是不被推荐的。如果要选择某个表内的所有字段,最好是按实全部写出来,例如:select t.aa, t.bb, t.cc, t.dd, ...
WHERE t.fid && 'S': t.fid 是数值型字段,不应该写成 字符比较的形式。这个对性能影响不大,是个编程规范的问题。
  toplist.php 的其他三条 sql 语句,都存在这些问题。如果要针对他的 sql 语句去优化 MySQL 结构,会带来不良的后果;如果直接改他的 toplist.php 程序,如果站长以后升级 toplist.php 又怕带来不兼容问题。于是我建议他干脆关闭首页四格插件。   关闭首页四格插件之后,CPU 降到 18% 左右震荡,表现非常良好。   如果是我来写首页四格的程序,我不会采用这种方案,我会用定时15分钟或30分钟查询一次数据库,将结果写入 TXT 文件或临时表,然后程序再从中读取,效率会高许多。   结论: 如果装了插件的论坛碰到 CPU 高负荷时,建议关掉插件再评估性能。
慎装第三方插件。没事不要乱插。:)
附4:补充笔记 :这篇文章,重要的是分析过程,而不是进行修正的那段代码   最近有几位在评论中留言,以及给我 EMAIL,说到将我在文中给出的 那8行 ALTER TABLE 代码,在他的出现 CPU 100% 的 dz 论坛上,用了之后没有效果。   我的解释如下:这段代码,不能保证在 dz 的所有版本下通用。具体问题,要具体分析。这段代码,是我在 Dizcus! 5.5.0 的版本的基本下进行分析得出的校正结果。其他的版本,不敢保证。   这篇文章的重点,并不是作为结果的这段代码,而是如何得出这个结果的分析过程。知道了原理,你自己一样可以分析。 附5: 相关文章: 解决一个 MySQL 服务器进程 CPU 占用 100%的技术笔记
liyihongcug 发表于
[i=s] 本帖最后由 liyihongcug 于
21:08 编辑 [/i] [url]http://www.cnkuai.cn/news/.htm[/url] [url]http://lgcpeter.iteye.com/blog/210461[/url]早上帮朋友一台服务器解决了 Mysql cpu 占用 100% 的问题,稍整理如下,希望对各位有所帮助。 朋友主机(Windows 2003 + IIS + PHP + MYSQL )近来 MySQL 服务进程 (mysqld-nt.exe) CPU 占用率总为 100% 高居不下。此主机有10个左右的 database, 分别给十个网站调用。据朋友测试,导致 mysqld-nt.exe cpu 占用奇高的是网站A,一旦在 IIS 中将此网站停止服务,CPU 占用就降下来了。一启用,则马上上升。 MYSQL CPU 占用 100% 的解决过程 今天早上仔细检查了一下。目前此网站的七日平均日 IP 为2000,PageView 为 3万左右。网站A 用的 database 目前有39个表,记录数 60.1万条,占空间 45MB。按这个数据,MySQL 不可能占用这么高的资源。 于是在服务器上运行命令,将 mysql 当前的环境变量输出到文件 output.txt: d:\web\mysql& mysqld.exe --help &output.txt 发现 tmp_table_size 的值是默认的 32M,于是修改 My.ini, 将 tmp_table_size 赋值到 200M: d:\web\mysql& notepad c:\windows\my.ini [mysqld] tmp_table_size=200M 然后重启 MySQL 服务。CPU 占用有轻微下降,以前的CPU 占用波形图是 100% 一根直线,现在则在 97%~100%之间起伏。这表明调整 tmp_table_size 参数对 MYSQL 性能提升有改善作用。但问题还没有完全解决。 于是进入 mysql 的 shell 命令行,调用 show processlist, 查看当前 mysql 使用频繁的 sql 语句: mysql& 反复调用此命令(每秒刷两次),发现网站 A 的两个 SQL 语句经常在 process list 中出现,其语法如下: SELECT t1.pid, t2.userid, t3.count, t1.date FROM _mydata AS t1 LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid LEFT JOIN _mydata_body AS t2 ON t1.pid=t3.pid ORDER BY t1.pid LIMIT 0,15 调用 show columns 检查这三个表的结构 : mysql& show columns from _ mysql& show columns from _ mysql& show columns from _mydata_ 终于发现了问题所在:_mydata 表,只根据 pid 建立了一个 primary key,但并没有为 userid 建立索引。而在这个 SQL 语句的第一个 LEFT JOIN ON 子句中: LEFT JOIN _myuser AS t3 ON t1.userid=t3.userid _mydata 的 userid 被参与了条件比较运算。于是我为给 _mydata 表根据字段 userid 建立了一个索引: mysql& ALTER TABLE `_mydata` ADD INDEX ( `userid` ) 建立此索引之后,CPU 马上降到了 80% 左右。看到找到了问题所在,于是检查另一个反复出现在 show processlist 中的 sql 语句: SELECT COUNT(*) FROM _mydata AS t1, _mydata_key AS t2 WHERE t1.pid=t2.pid and t2.keywords = '孔雀' 经检查 _mydata_key 表的结构,发现它只为 pid 建了了 primary key, 没有为 keywords 建立 index。_mydata_key 目前有 33 万条记录,在没有索引的情况下对33万条记录进行文本检索匹配,不耗费大量的 cpu 时间才怪。看来就是针对这个表的检索出问题了。于是同样为 _mydata_key 表根据字段 keywords 加上索引: mysql& ALTER TABLE `_mydata_key` ADD INDEX ( `keywords` ) 建立此索引之后,CPU立刻降了下来,在 50%~70%之间震荡。 再次调用 show prosslist,网站A 的sql 调用就很少出现在结果列表中了。但发现此主机运行了几个 Discuz 的论坛程序, Discuz论坛的好几个表也存在着这个问题。于是顺手一并解决,cpu占用再次降下来了。 至此,问题解决。 解决 MYSQL CPU 占用 100% 的经验总结 1. 增加 tmp_table_size 值。mysql 的配置文件中,tmp_table_size 的默认大小是 32M。如果一张临时表超出该大小,MySQL产生一个 The table tbl_name is full 形式的错误,如果你做很多高级 GROUP BY 查询,增加 tmp_table_size 值。 这是 mysql 官方关于此选项的解释: tmp_table_size This variable determines the maximum size for a temporary table in memory. If the table becomes too large, a MYISAM table is created on disk. Try to avoid temporary tables by optimizing the queries where possible, but where this is not possible, try to ensure temporary tables are always stored in memory. Watching the processlist for queries with temporary tables that take too long to resolve can give you an early warning that tmp_table_size needs to be upped. Be aware that memory is also allocated per-thread. An example where upping this worked for more was a server where I upped this from 32MB (the default) to 64MB with immediate effect. The quicker resolution of queries resulted in less threads being active at any one time, with all-round benefits for the server, and available memory. 2. 对 WHERE, JOIN, MAX(), MIN(), ORDER BY 等子句中的条件判断中用到的字段,应该根据其建立索引 INDEX。 索引被用来快速找出在一个列上用一特定值的行。没有索引,MySQL不得不首先以第一条记录开始并然后读完整个表直到它找出相关的行。表越大,花费时间越 多。如果表对于查询的列有一个索引,MySQL能快速到达一个位置去搜寻到数据文件的中间,没有必要考虑所有数据。如果一个表有1000行,这比顺序读取 至少快100倍。所有的MySQL索引(PRIMARY、UNIQUE和INDEX)在B树中存储。 根据 mysql 的开发文档: 索引 index 用于: & &o 快速找出匹配一个WHERE子句的行 & &o 当执行联结(JOIN)时,从其他表检索行。 & &o 对特定的索引列找出MAX()或MIN()值 & &o 如果排序或分组在一个可用键的最左面前缀上进行(例如,ORDER BY key_part_1,key_part_2),排序或分组一个表。如果所有键值部分跟随DESC,键以倒序被读取。 & &o 在一些情况中,一个查询能被优化来检索值,不用咨询数据文件。如果对某些表的所有使用的列是数字型的并且构成某些键的最左面前缀,为了更快,值可以从索引树被检索出来。 假定你发出下列SELECT语句: mysql& SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2; 如果一个多列索引存在于col1和col2上,适当的行可以直接被取出。如果分开的单行列索引存在于col1和col2上,优化器试图通过决定哪个索引将找到更少的行并来找出更具限制性的索引并且使用该索引取行。开发人员做 SQL 数据表设计的时候,一定要通盘考虑清楚。
renxiao2003 发表于
谢谢分享,我还没有碰到过啊。

我要回帖

更多关于 mysql按多列分组排序 的文章

 

随机推荐