iMySQL(一)

1 如何在数据库中存储层级结构


iMySQL(一)_第1张图片

(1) 邻接表模型


iMySQL(一)_第2张图片
  • 求节点的路径
    举例来说,“Cherry”所在的路径为Food > Fruit > Red > Cherry。在这里,我们可以从Cherry开始查起,然后递归查询查询节点前的节点,直到某节点的父节点ID为0(Food)。

  • 优点
    简单易懂

  • 缺点
    执行起来效率低下。我们对于每个结果,期望只需要一次查询;可是当使用邻接表模型时嵌套的递归使用了多次查询,当树很大的时候,这种慢就会表现得尤为明显。

上帝是公平的,当在执行时效率低下,意味着可以增加预处理的程度。

(2)MPTT(修改过的前序遍历算法)

  • 原理
    现在我们把树“横”着放。如下图所示,我们首先从根节点(“Food”)开始,先在它左侧标记“1”,然后我们到“Fruit”,左侧标记“2”,接着按照前序遍历的顺序遍历完树,依次在每个节点的左右侧标记数字。
iMySQL(一)_第3张图片
  • 实现
iMySQL(一)_第4张图片
  • 打印树
    如果要想打印树,你只需要知道你要检索的节点。比如,想要打印“Fruit”的子树,可以查询左数大于2而小于11的节点。
SELECT * FROM tree WHERE lft BETWEEN 2 AND 11;
  • 求节点的路径
    对于某节点,我们只需求出左数值小于其左数值、右数大于其右数的所有节点。比如说“Cherry”这个节点(4-5)
SELECT title FROM tree WHERE lft < 4 AND rgt > 5 ORDER BY lft ASC;
  • 增加节点
    我们想添加“Strawberry“到”Red“节点下,那么“Red”节点的右数就得从6到8,而“Yellow”就得从7-10变成9-12,以此类推。更新Red节点就意味着大于5的左数和右数都要增加2。
UPDATE tree SET rgt=rgt+2 WHERE rgt>5;
UPDATE tree SET lft=lft+2 WHERE lft>5;

INSERT INTO tree SET lft=6, rgt=7, title='Strawberry';
  • 优点
    查询的时候只需要一条SQL语句

2 进入正题

  • Mysql架构
    • Parser
      将用户的查询语句进行解析,并创建一个内部的数据结构——分析树
    • Optimizer
      各种优化,例如重写查询、选择读取表的顺序,以及使用哪个索引等。
iMySQL(一)_第5张图片
  • 类目表结构(是否可以改进?)
CREATE TABLE `itemcats` (
  `cid` int(11) NOT NULL,
  `parent_cid` int(11) DEFAULT NULL,
  `name` varchar(50) NOT NULL,
  `is_parent` tinyint(1) NOT NULL,
  `status` varchar(20) DEFAULT NULL,
  `sort_order` int(11) DEFAULT NULL,
  `lft` int(11) NOT NULL,
  `rght` int(11) NOT NULL,
  `level` int(11) NOT NULL,
  PRIMARY KEY (`cid`),
  KEY `parent_cid` (`parent_cid`),
  KEY `lft_rght` (`lft`,`rght`),
  KEY `level` (`level`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 为什么InnoDB表要建议用自增列做主键?
    如果InnoDB表的数据写入顺序能和B+树索引的叶子节点顺序一致的话,这时候存取效率是最高的
    • 使用自增列(INT/BIGINT类型)做主键,这时候写入顺序是自增的,和B+数叶子节点分裂顺序一致;
    • 如果一个InnoDB表又没有显示主键,又有可以被选择为主键的唯一索引,但该唯一索引可能不是递增关系时(例如字符串、UUID、多字段联合唯一索引的情况),该表的存取效率就会比较差。
  • 数值类型
iMySQL(一)_第6张图片
  • 字符串类型
    • char(n)和varchar(n)中括号中n代表字符的个数,并不代表字节个数,所以当使用了中文的时候(UTF8)意味着可以插入m个中文,但是实际会占用m*3个字节。
    • 同时char和varchar最大的区别就在于char不管实际value都会占用n个字符的空间,而varchar只会占用实际字符应该占用的空间+1,并且实际空间+1<=n。
    • 超过char和varchar的n设置后,字符串会被截断。
    • char在存储的时候会截断尾部的空格,varchar和text不会。
    • varchar会使用1-3个字节来存储长度,text不会。
iMySQL(一)_第7张图片

你可能感兴趣的:(iMySQL(一))