0
Posted on Friday, September 22, 2017 by 醉·醉·鱼 and labeled under
最近在做exercise.io上面的题练习Ruby,顺便分享一下自己的代码。
http://exercism.io/exercises/ruby/kindergarten-garden/readme

这道题相对比较简单,主要是用each_slice进行一次分组,并且通过Hash做一个key-value转换。最后就只需要按照students的序号,找到之前分好组里对应需要的plants就行了。有趣的是,测试用例里面是通过student的名字在找其拥有的plants,那就需要点元编程的技巧了。这里需要用到define_singleton_method去动态定义以student命名的方法。

class Garden
  DEFAULT_STUDENTS = %w(alice bob charlie david eve fred ginny harriet ileana joseph kincaid larry)

  PLANTS = {
    'R' => :radishes,
    'C' => :clover,
    'G' => :grass,
    'V' => :violets
  }

  def initialize(plants, students=DEFAULT_STUDENTS)
    @plants = plants
    @students = students.sort
    distribute_plants
  end

  def distribute_plants
    # 将两行plants拆分成每两个一组,并对每个plant进行映射转换('R'=>:radishes)
    plants_grouped = @plants.split("\n")
                            .map { |r| r.chars #每一行plants
                                        .each_slice(2) #每两个一组
                                        .map { |plants|
                                          plants.map { |plant| PLANTS[plant] } #每个plant转换一次
                                            }
                                          }
    # 给每个student分配plants
    @students.each_with_index do |s, i|
      break if plants_grouped.first.size < i + 1 # plants不够,就不再分配给student了
      #创建singleton method,因为每个garden对应的plants分配是不一样的。define_method是对整个Class创建实例方法
      define_singleton_method(s.downcase) do
        plants_grouped.map { |e| e[i] }.flatten # 通过索引i,找到student对应的那组plant
      end
    end
  end

end
0
Posted on Wednesday, September 06, 2017 by 醉·醉·鱼 and labeled under
SQL SERVER的index是按照B+tree来存储的。在dm_db_database_page_allocations可以看到这类page的type是2,即index page。
每个index page存储着key - pointer关系,其childPage可能还是intermediate page,也可能是leaf page。leaf page就存储着具体的data。

如下图中的page 623876就是一个intermediate page。

其数据即存储着ChildPageId和key pointer。比如这个例子中,id小于477的,都存在page 623874上。其中level表示该page是root node page。


用fn_PhysLocCracker来实验一下,就可以验证上面的观点。




DROP TABLE LargeTable

CREATE TABLE LargeTable (keyval int, 
    dataval int,
    constraint pk_largetable primary key (keyval)
    )

INSERT INTO LargeTable(keyval, dataval)
select n, rand(10) 
from dbo.GetNums(10000000)


SELECT allocated_page_file_id as PageFID, allocated_page_page_id as PagePID,
       object_id as ObjectID, partition_id AS PartitionID,
       allocation_unit_type_desc as AU_type, page_type as PageType
FROM sys.dm_db_database_page_allocations(db_id('event_service'), object_id('LargeTable'),
                                          1, null, 'DETAILED');
GO

DBCC TRACEON (3604); 
GO 
DBCC PAGE ('event_service', 1, 623876, 3); 
GO

DBCC TRACEON (3604); 
GO 
DBCC PAGE ('event_service', 1, 608307, 3); 
GO

select *
from LargeTable t
CROSS APPLY sys.fn_PhysLocCracker(%%physloc%%) AS flc
WHERE keyval < 478

0
Posted on Wednesday, September 06, 2017 by 醉·醉·鱼 and labeled under
同事问了一个问题,在drop default constraint之后,是否会引起大的IO。答案是,No。

其实两年我就问过这个问题,结果还是被无情地打脸了,忘记完了。
https://dba.stackexchange.com/questions/90771/default-value-stays-after-i-dropped-the-default-constraint

长话短说,在每次创建default constraint的时候,在system_internals_partition_columns表内都会记录default value,从而实现所谓的metadata change。即sql server 2012以后,把一个column从NULL改为NOT NULL WITH DEFAULT CONSTRAINT是metadata change。随后删除这个constraint并不会改变system_internals_partition_columns里面值,也不会引起大的IO。

这个可以引出其他的问题:比如,有一个huge 表,如何把一列所有NULL改为指定值?可以加一个default constraint,随后再drop这个constraint。

http://rusanu.com/2011/07/13/online-non-null-with-values-column-add-in-sql-server-11/


IF OBJECT_ID('LobData') IS NOT NULL
    DROP TABLE dbo.LobData

create table dbo.LobData
(
    ID int not null
);

insert into dbo.LobData(ID) 
values (1);


SELECT allocated_page_file_id as PageFID, allocated_page_page_id as PagePID,
       object_id as ObjectID, partition_id AS PartitionID,
       allocation_unit_type_desc as AU_type, page_type as PageType
FROM sys.dm_db_database_page_allocations(db_id('event_service'), object_id('LobData'),
                                          null, null, 'DETAILED');
GO

DBCC TRACEON (3604); 
GO 
DBCC PAGE ('event_service', 1, 610871, 3); 
GO


ALTER TABLE LobData ADD DATA VARCHAR(20) NOT NULL constraint df_lobdata default('yes')

insert into dbo.LobData(ID) 
values (2);

select * from LobData

ALTER TABLE LOBDATA DROP CONSTRAINT df_lobdata;


ALTER TABLE LobData ADD constraint df_lobdata default('no') for data;

insert into dbo.LobData(ID) 
values (3);

select * from LobData


select pc.* 
from sys.system_internals_partitions p
join sys.system_internals_partition_columns pc on p.partition_id = pc.partition_id
where p.object_id = object_id('lobdata');

0
Posted on Monday, September 04, 2017 by 醉·醉·鱼 and labeled under
同事瞎折腾,问了一个问题:
起100个线程连接数据库,如何保证同一个query得到100条不同的结果。

在SQL SERVER下,是可以通过这么实现的。每次读的时候,强制加一个U/X锁,这个时候,再用HINT READPAST,即可跳过已经被锁住的记录,读取下一条记录。

BEGIN TRANSACTION

SELECT TOP 1 * FROM T1 WITH(READPAST, UPDLOCK)

微软官网这么解释
READPAST
Specifies that the Database Engine not read rows that are locked by other transactions. When READPAST is specified, row-level locks are skipped but page-level locks are not skipped.

但是这里还是会发生LOCK escalate的,即key lock会升级成为page lock,或者table lock。

https://docs.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-table
0
Posted on Tuesday, August 29, 2017 by 醉·醉·鱼 and labeled under



  1. def...end, class...end, module...end都是作用域门,进入他们就会出现新的scope
  2. block是特殊的scope,block中initialize的局部变量在外部没法访问
  3. 扁平作用域可以用,define_method, Class.new, Module.new来实现。
0
Posted on Friday, August 25, 2017 by 醉·醉·鱼 and labeled under
钩子们,来吧

https://www.sitepoint.com/rubys-important-hook-methods/

# included
module Person
  
  def name
    puts "My name is Person"
  end

  module ClassMethods
    def class_method_1
      puts "Class method is called"
    end
  end

  module InstanceMethods
    def instance_method_1
      puts "instance method is called"
    end
  end

  def self.included(receiver)
    receiver.extend         ClassMethods
    receiver.send :include, InstanceMethods
    puts "#{receiver} included #{self}"
  end
end


class User
  include Person
end

user = User.new
user.name
user.instance_method_1
user.class.class_method_1
p User.ancestors

puts "="*16
# extended
module Animal
  def name
    puts "I'm an animal"
  end

  def self.extended(receiver)
    puts "#{receiver} extended #{self}"
  end
end

class Dog
  extend Animal
end

Dog.name

puts "="*16
# prepended
module Ship
  def name
    puts "I'm a ship"
  end

  module ClassMethods
    def class_method_1
      puts "Class method is called"
    end
  end

  module InstanceMethods
    def instance_method_1
      puts "instance method is called"
    end
  end

  def self.prepended(receiver)
    receiver.extend         ClassMethods
    receiver.send :prepend, InstanceMethods
    puts "#{receiver} prepended #{self}"
  end

end

class Boat
  prepend Ship

  def name
    puts "I'm a boat. I should be overried by Ship so you won't see me."
  end
end

Boat.new.name
Boat.new.instance_method_1
p Boat.ancestors
Boat.class_method_1

puts "="*16
# inherited
class Parent

  def self.inherited(child_class)
    puts "#{child_class} inherits #{self}"
  end

  def name
     "My name is Parent"
  end
end

class Child < Parent
end

puts Child.new.name # => My name is Parent
p Child.ancestors

puts "="*16
# method_missing
class Coffee
  def price
    2
  end

  def name
    "I'm a coffee"
  end
end

class Milk
  def initialize(coffee)
    @coffee = coffee
  end
  
  def price
    super + 0.2
  end
  
  def method_missing(meth, *args)
    "#{meth} not defined on #{self}"
    if @coffee.respond_to?(meth)
      @coffee.send(meth, *args)
    else
      super
    end
  end

end

coffee = Coffee.new
coffee_with_milk = Milk.new(coffee)
p coffee_with_milk.price
p coffee_with_milk.name
p coffee_with_milk.class.instance_methods(false) #you won't see #name method






0
Posted on Friday, August 25, 2017 by 醉·醉·鱼 and labeled under
Ruby中的继承不仅仅可以继承实例方法,还可以继承类方法。但是,对于MIXIN的类方法,只能够用BASE.EXTEND来实现了。


class Person
  def self.method_1
    puts "I'm Person class method 1"
  end

  class << self
    def method_2
      puts "I'm Person class method 2"
    end
  end

  def method_3
    puts "I'm instance method 3"
  end


  protected

  def protected_method_1
    puts "I'm protected_method_1"
  end

  private

  def private_method_1
    puts "I'm private_method_1"
  end


end

class Phoenix < Person
  
  def method_4
    puts "I'm instance method 4"
  end

  def call_protected_method_1
    puts "going to call protected_method_1 from Phoenix"
    protected_method_1
  end

  def call_private_method_1
    puts "going to call private_method_1 from Phoenix"
    private_method_1
  end
end

Phoenix.method_1 #ok to inherit class methods
Phoenix.method_2 #ok to inherit class methods

phoenix = Phoenix.new

phoenix.method_3 #ok to inherit instance methods
phoenix.method_4 #ok

phoenix.call_protected_method_1 #ok to call protected method in parent class
# phoenix.protected_method_1 # failed. you could not call it directly
phoenix.call_private_method_1 #ok to call private method in parent class
# phoenix.private_method_1 #failed

# However, mixin class methods could not be inherited unless call base.extend