@sun1752709589 very good! 👍
@sun1752709589 innodb 中,建立索引如果没有添加 id,会自动补加上。手动加上 id 的话,就减少了一丢丢数据库消耗的资源。之前,我问过我们的 DBA。所以现在我们添加索引的时,会主动将 id,添加上。
mysql> CREATE TABLE foo (id SERIAL PRIMARY KEY, bar CHAR(10));
Query OK, 0 rows affected (2.60 sec)
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`bar` char(10) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHA
mysql> INSERT INTO foo (bar) VALUES
-> ('testing'), ('testing'), ('testing'), ('testing'), ('testing'),
-> ('testing'), ('testing'), ('testing'), ('testing'), ('testing');
Query OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> select * from foo;
+----+---------+
| id | bar |
+----+---------+
| 1 | testing |
| 2 | testing |
| 3 | testing |
| 4 | testing |
| 5 | testing |
| 6 | testing |
| 7 | testing |
| 8 | testing |
| 9 | testing |
| 10 | testing |
+----+---------+
10 rows in set (0.00 sec)
mysql> DELETE FROM foo WHERE id BETWEEN 4 AND 7;
Query OK, 4 rows affected (0.01 sec)
mysql> select * from foo;
+----+---------+
| id | bar |
+----+---------+
| 1 | testing |
| 2 | testing |
| 3 | testing |
| 8 | testing |
| 9 | testing |
| 10 | testing |
+----+---------+
6 rows in set (0.00 sec)
mysql> INSERT INTO foo (bar) VALUES
-> ('testing'), ('testing'), ('testing'), ('testing'), ('testing'),
-> ('testing'), ('testing'), ('testing'), ('testing'), ('testing');
Query OK, 10 rows affected (0.01 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> select * from foo;
+----+---------+
| id | bar |
+----+---------+
| 1 | testing |
| 2 | testing |
| 3 | testing |
| 8 | testing |
| 9 | testing |
| 10 | testing |
| 11 | testing |
| 12 | testing |
| 13 | testing |
| 14 | testing |
| 15 | testing |
| 16 | testing |
| 17 | testing |
| 18 | testing |
| 19 | testing |
| 20 | testing |
+----+---------+
16 rows in set (0.02 sec)
mysql> status;
--------------
/usr/local/bin/mysql Ver 14.14 Distrib 5.6.16, for osx10.9 (x86_64) using EditLine wrapper
如果能找一个反证,证明某些情况下不是按照主键 正序排序就完美了。
mysql> select SQL_NO_CACHE count(id) from g_d_outs\G;
*************************** 1. row ***************************
count(id): 69008543
1 row in set (10.76 sec)
ERROR:
No query specified
如果你想得到近似的统计值,使用 下面的这个方式 查找 Rows
值,这种方式是非常快的。
mysql> show table status where name = 'g_d_outs'\G;
*************************** 1. row ***************************
Name: g_d_outs
Engine: InnoDB
Version: 10
Row_format: Compact
Rows: 69008796
Avg_row_length: 71
Data_length: 4965007360
Max_data_length: 0
Index_length: 3560964096
Data_free: 5242880
Auto_increment: 138022949
Create_time: 2015-08-14 18:46:13
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: ??????????
1 row in set (0.01 sec)
或者使用 EXPLAIN 其中 rows 的返回值,也是一个近似值。
mysql> explain select id from g_d_outs;
+----+-------------+-----------------+-------+---------------+------------------------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+------------------------+---------+------+----------+-------------+
| 1 | SIMPLE | g_d_outs | index | NULL | idx_g_d_stdate | 3 | NULL | 69008796 | Using index |
+----+-------------+-----------------+-------+---------------+------------------------+---------+------+----------+-------------+
1 row in set (0.00 sec)
In the SQL world, order is not an inherent property of a set of data. Thus, you get no guarantees from your RDBMS that your data will come back in a certain order -- or even in a consistent order -- unless you query your data with an ORDER BY clause.
Combining TOP with ORDER BY adds determinism to the set of rows returned. Without the ORDER BY, the set of rows returned depends on the query plan and may even vary from execution to execution. Always use ORDER BY if you expect a well-defined and consistent order in your result set. Never rely on how your database may store the rows on disk (e.g. via a clustered index) to guarantee a certain ordering of data in your queries.
Never rely on how your database may store the rows on disk (e.g. via a clustered index) to guarantee a certain ordering of data in your queries.
http://dba.stackexchange.com/questions/5774/why-is-ssms-inserting-new-rows-at-the-top-of-a-table-not-the-bottom/5775#5775 如果能有具体的理论依据就好了。看来我得认真研究下这个问题。
3Q for @foghost
SELECT `artwork_transactions`.`id`,
`artwork_transactions`.`artwork_id`,
`artwork_transactions`.`transaction_date`,
`artwork_transactions`.`trans_type`,
`artwork_transactions`.`display_price`,
`artwork_transactions`.`icon_img_url`
FROM `artwork_transactions`
INNER JOIN `artworks` ON `artwork_transactions`.`artwork_id` = `artworks`.`id`
WHERE `artworks`.`artist_id` = 28896
ORDER BY `artwork_transactions`.`transaction_date` ASC LIMIT 25
OFFSET 0
方便表结构描述一下么?
解决方式大概有如下:
1、指定正确的驱动表 artwork_transactions 或 artworks。如果要在 artwork_transactions 这个表上面排序,就需要指定 artwork_transactions 为驱动表。所以需要将 INNER JOIN 改成 STRAIGHT_JOIN。
2、建立artwork_transactions
.artwork_id
,artwork_transactions
.trans_type
,artwork_transactions
.display_price
, artwork_transactions
.icon_img_url
, artwork_transactions
.id
,覆盖索引
3、在 artworks
上建立 artworks
.artist_id
索引。
根据如上方式优化之后,SQL 查询肯定会很快!
罗老师呀,👍!
@winnie MySQL 运用挺广泛的
@so_zengtao 不用谢。共勉
#3 楼 @so_zengtao 在排序时,null 值被认为是最大的,这里修改了下 在排序时,null 值被认为是最大的(Oracle)
SQLServer 和 MySQL 认为 null 最小,Oracle 认为 null 最大
3Q , 【NULLS】Oracle 对 SQL 排序后 NULL 值位置的“特殊关照”
NULLS FIRST / NULLS LAST 是 Oracle 的命令,MySQL 并没有类似命令,只能通过其他方式实现。
@hooopo 👍,UNION 是一种不错的方式。
#1 楼 @luolinae86 不用客气
不错不错
@sleepless 以及《高性能 MySQL》第三版,121 页
这是一个通用的设计实践,在“查找表”时采用整数主键避免采用基于字符串的值进行关联
及后面的 4.1.6 选择标识符 (identifier) 中的描述
所以为标识列选择数据类型时,应该选择跟表关联表中的对应列一样的类型 整数通常是标识列最好的选择,因为他们很快并且可以使用 AOTO_INCREMENT
所以综上所述,使用与业务无关的主键 ID 是一个非常不错的选择。
Nginx 还是很有必要的,建议仁兄好好研究下
@kakaxi2 实际上由于 id 是聚簇索引,并没有一个单独的索引树存 id,因此在磁盘上,id 索引树的叶节点上就是数据。InnoDB 以 page 为单位读取,在取 id 的过程中,必须将所有的数据读入。仁兄,你说的是这个意思么?
#9 楼 @so_zengtao 但是,如果你不小心合并和别人错误的分支代码,而且已经向前推进了好多步,最后才发现问题,你怎么解决呢?cherry-pick 就是解决这种情况的。
#15 楼 @kakaxi2 一般情况来说呢,在 InnoDB 中,将 id
作为索引的最后一个列,并且默认情况下,设置主键索引的。因为自增主键,不会重复,那么就代表的高的索引基数(Cardinality),查询,如
SELECT * FROM table ORDER BY id desc limit 10;
就会很有效果。
有些查询,按照创建时间倒叙排列
SELECT * FROM table ORDER BY created_at desc ;
其实可以改写成
SELECT * FROM table ORDER BY id desc;
这种情况下,还是蛮实用的。因为在 created_at
上创建索引的代价,会远远大于在 id
上创建索引的代价。
所以创建一个 主键 id,并且设置为自增,还是有必要的。
不太明白 这里的 ** 不会经常改变的列 ** 是什么意思呢?
@xiaoronglv you are right!
@pathbox 恩。因为有些同事,或小伙伴问,为什么要给表设置主键。其实 主键是一个表的最基本设置。