• @sun1752709589 very good! 👍

  • @sun1752709589 innodb 中,建立索引如果没有添加 id,会自动补加上。手动加上 id 的话,就减少了一丢丢数据库消耗的资源。之前,我问过我们的 DBA。所以现在我们添加索引的时,会主动将 id,添加上。

  • @foghost

    
    
    
    
    
    
    
    
    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
    

    如果能找一个反证,证明某些情况下不是按照主键 正序排序就完美了。

  • @xiaoronglv

    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)
    
    
    
  • @foghost

    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

  • @prajnamas

    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_idartwork_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 是一种不错的方式。

  • #2 楼 @hooopo 在索引列上,排序时使用函数,肯定是不能用到索引的。 这里亦修改成这样。

    SELECT name, points
    FROM users
    WHERE points is not null
    ORDER BY points DESC
    

    金钱比较。我还是建议在数据库中,使用整形来存储,显示时可以自定义 format 展示为浮点数格式,比较时,使用原始的整数进行比较即可。

  • #1 楼 @luolinae86 不用客气

  • 不错不错

  • MySQL 为什么需要一个主键 at 2015年08月09日

    @sleepless 以及《高性能 MySQL》第三版,121 页

    这是一个通用的设计实践,在“查找表”时采用整数主键避免采用基于字符串的值进行关联

    及后面的 4.1.6 选择标识符 (identifier) 中的描述

    所以为标识列选择数据类型时,应该选择跟表关联表中的对应列一样的类型 整数通常是标识列最好的选择,因为他们很快并且可以使用 AOTO_INCREMENT

    所以综上所述,使用与业务无关的主键 ID 是一个非常不错的选择。

  • MySQL 为什么需要一个主键 at 2015年08月09日
  • Nginx 还是很有必要的,建议仁兄好好研究下

  • MySQL 为什么需要一个主键 at 2015年08月06日

    #24 楼 @kakaxi2 仁兄,能详细说明下这种方式的具体应用场景和这种方式的优势么?

  • MySQL 为什么需要一个主键 at 2015年07月28日

    @kakaxi2 实际上由于 id 是聚簇索引,并没有一个单独的索引树存 id,因此在磁盘上,id 索引树的叶节点上就是数据。InnoDB 以 page 为单位读取,在取 id 的过程中,必须将所有的数据读入。仁兄,你说的是这个意思么?

  • git cherry-pick 最佳实践 at 2015年07月28日

    #9 楼 @so_zengtao 但是,如果你不小心合并和别人错误的分支代码,而且已经向前推进了好多步,最后才发现问题,你怎么解决呢?cherry-pick 就是解决这种情况的。

  • MySQL 为什么需要一个主键 at 2015年07月27日

    #4 楼 @hooooopo nice,👍

  • MySQL 为什么需要一个主键 at 2015年07月27日

    #3 楼 @est 👍

  • MySQL 为什么需要一个主键 at 2015年07月27日

    #8 楼 @sevk 你可以试一试哦,在各种不同情况下,会有不同的反应。InnoDB,创建索引的时候,默认会把 id 当做索引中的最后一列。自增不一定最好,但是还是希望主键不要重复。

  • MySQL 为什么需要一个主键 at 2015年07月27日

    #10 楼 @echooo 根据不同的业务需求选择合适的主键 id。

  • MySQL 为什么需要一个主键 at 2015年07月27日

    #11 楼 @winnie Rails 做的确实很好,经常会有这种,按照创建时间,或更新时间倒叙排列的需求。

  • MySQL 为什么需要一个主键 at 2015年07月27日

    #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,并且设置为自增,还是有必要的。

    不太明白 这里的 ** 不会经常改变的列 ** 是什么意思呢?

  • #4 楼 @lex 别着急呢,正在收集整理呢

  • MySQL 为什么需要一个主键 at 2015年07月26日
  • MySQL 为什么需要一个主键 at 2015年07月21日

    @xiaoronglv you are right!

  • MySQL 为什么需要一个主键 at 2015年07月07日

    @pathbox 恩。因为有些同事,或小伙伴问,为什么要给表设置主键。其实 主键是一个表的最基本设置。