0
Posted on Monday, January 16, 2017 by 醉·醉·鱼 and labeled under
可能大家都习惯了SELECT * FROM TABLE,或者SELECT DATA FROM TABLE WHERE ID = 1。一般来说,无非就是INDEX SEEK,或者CLUSTERED INDEX SCAN。但下面这个例子,却两者都不是。


IF OBJECT_ID('DBO.T1') IS NOT NULL
    DROP TABLE t1

CREATE TABLE T1(
    ID BIGINT,
    ANOTHER_ID INT,
    DATA VARCHAR(200),
    CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED (ID)
)

INSERT INTO T1(ID, ANOTHER_ID,DATA)
SELECT n,
    n%4, 
    CASE WHEN n % 4 = 1 THEN 'pHoEnIx'
                    WHEN n % 4 = 2 THEN 'eRiK'
                    WHEN n % 4 = 3 THEN 'dBe'
                    ELSE 'Papa'
                    END
FROM dbo.getnums(50000)

CREATE NONCLUSTERED INDEX idx_t1_another_id ON t1(another_id)

SELECT ID FROM T1
SELECT DATA FROM T1



对于第二个SELECT query,很明显,DATA不被包含在non-clustered index里面,所以只能够用CLUSTERED INDEX SCAN。但是第一个SELECT query,却是INDEX SCAN。WHY?是错误的执行计划?不是。
事实是,很明显non-clustered index占用的空间比clustered index小,而且non-clustered index的最后一个节点就是ID,不用它用谁。此外,如果一个表上面有多个non-clustered index,SQL SERVER会用INDEX占用最小的INDEX。



如果一切这么简单就好,这样的query单独列出来可能稍微仔细看就发现问题了。继续上面的SQL script


CREATE TABLE T2(
    ID INT
)

INSERT INTO T2(ID)
SELECT n*4
FROM dbo.getnums(50000)

DELETE FROM T2 WHERE NOT EXISTS(SELECT 1 FROM T1 WHERE T1.ID = t2.ID)



当T2的数据级和T1的数据级差不多的时候,SQL SERVER就不会SCAN T2再去T1里面进行CLUSTERED INDEX SEEK。相反,SQL SERVER会对两个表都进行SCAN,再HASH MATCH。这里很隐晦地把SELECT ID FROM TABLE转换成SELECT 1 FROM TABLE WHERE ID ...。满心以为这个很明显的是CLUSTERED INDEX SEEK啊, WHERE ID = 啊。等你看执行计划的时候,你就傻眼了。啥?!INDEX SCAN??


一旦是INDEX SCAN,一般都是PAGE级别的锁,放在non-clustered index上,一不留神就会导致长时间BLOCKING。
0
Posted on Monday, November 21, 2016 by 醉·醉·鱼 and labeled under , ,
貌似EI Capitan和以前的版本的安装有些差别,记录一下。大体来说,你需要安装下面3个部分。

  • Oracle Instant Client
  • ruby-oci8 gem
  • activerecord-oracle_enhanced-adapter gem

安装Oracle Instant Client

去Oracle官网下载下面几个包,并按照 http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html
  1. instantclient-basic-macos.x64-12.1.0.2.0.zip
  2. instantclient-sqlplus-macos.x64-12.1.0.2.0.zip
  3. instantclient-sdk-macos.x64-12.1.0.2.0.zip
解压到/opt/oracle/instantclient_12_1

cd ~

unzip instantclient-basic-macos.x64-12.1.0.2.0.zip
unzip instantclient-sqlplus-macos.x64-12.1.0.2.0.zip
unzip instantclient-sdk-macos.x64-12.1.0.2.0.zip

3. 创建link


cd /opt/oracle/instantclient_12_1
ln -s libclntsh.dylib.12.1 libclntsh.dylib

Note: OCCI programs will additionally need:


ln -s libocci.dylib.12.1 libocci.dylib

4. 配置PATH


export ORACLE_HOME=/opt/oracle/instantclient_12_1
export OCI_DIR=/opt/oracle/instantclient_12_1
export PATH=$ORACLE_HOME:$PATH
export TNS_ADMIN=$HOME
export NLS_LANG="AMERICAN_AMERICA.UTF8"

安装Gem

gem install 'ruby-oci8' -v '~> 2.1.0'
gem install 'activerecord-oracle_enhanced-adapter' -v '~> 1.5.0'


测试


ActiveRecord::Base.establish_connection(
    :adapter => "oracle_enhanced",
    :database => "database",
    :username => "username",
    :password => "password")

    cursor = ActiveRecord::Base.connection.execute("SELECT 1 n FROM table")

    # query data
    result_data = []

    result_data << cursor.column_metadata.map { |e| e.name }

    while row = cursor.fetch
        result_data << row
    end

引用
  1. http://stackoverflow.com/questions/36811473/ruby-oci8-installation-error-in-mac-el-capitan
  2. https://craig.io/setting-up-a-rails-development-environment-with-oracle/
0
Posted on Thursday, November 17, 2016 by 醉·醉·鱼 and labeled under


  1. ODBC。Open Database Connectivity,是很老的一个数据库连接API。现在基本上没有用了。
  2. 微软后来开发了OLE DB,算是ODBC的替代品,同时支持更多的数据源,比如spreadsheets
  3. ADO.NET是基于.NET framework来连接关系型和非关系型数据库。看上去像ADO的进化版,实际上完全是全新的东西。
  4. JDBC。同ODBC,不过是给JAVA用的。
  5. JDBC有两款driver,一个是微软自己开发的sqljdbc4,另外一个是jtds。前者不支持NamedPipe。
  6. 可以通过
    jdbc:jtds:sqlserver://./DatabaseName;instance=LOCALDB#88893A09;namedPipe=true 连接namedPipe
  7. jtds是基于FreeTds。
  8. ruby下面tiny_tds也是基于FreeTds的。





0
Posted on Tuesday, October 11, 2016 by 醉·醉·鱼 and labeled under
谨以此文纪念我已经“死”去的各种老师,我对不起你们,我都忘记完了。


首先在Excel中建立A2:B7的数据。A8,B8分别是A和B的平均数。

根据协方差公式,C列为A2-$A$8,D列为B2-$B$8,E为C2*D2。最后求和得到118.29。再除以N-1,得到协方差23.658。也可以通过=COVARIANCE.S(A2:A7, B2:B7)直接得到。

然后开始计算样本标准差。可以通过=STDEV.S(A2:A7)直接获得7.9633,这里就不一步步计算了。如下图G1和H1.


根据相关系数公式,可以得到相关系数为=F1/G1/H1 0.655979. 也可以通过=CORREL(A2:A7, B2:B7)得到。但是这里的相关系数和趋势图中的β 0.3731相差挺大的。原来,图中的β是通过=F1/G1/G1 得到的,而G1为A:A的样本标准差。因此,β = 0.3731

由于y=βx+ε,带入A和B的平均值,得到ε为1.3417。

其实,你也可以直接通过=SLOPE(B2:B7, A2:A7)计算β,=INTERCEPT(B2:B7, A2:A7)计算ε。


那最后就是这个决定系数R²。切记,不要和相关系数r混淆了。这里的R²是用来衡量前面相关系数β的准确性的,取值为0到1。数值越大,表示β越准确。计算公式为根据线性公式算出的期望方差除以样本方差。

将A列的各值带入公式y=βx+ε,得到J列,再减去平均值$B$8得到K列。将D列和K列分别平方求和,在用M8/L8即可得到决定系数0.430308。也可以通过=RSQ(B2:B7, A2:A7)得到。

0
Posted on Monday, September 19, 2016 by 醉·醉·鱼 and labeled under ,
Kalen最近参加了24 hours of PASS,主题是《Locking, Blocking, Versions: Concurrency for Maximum Performance》。但实际上只讲了locking的一些基本概念,还有很多没有讲到。不过作为回顾,也是不错的。






  1. 在SQL SERVER,最基本的两种lock是shared lock(S)和exclusive lock(X)
  2. UPDATE lock是一个混合模式,出现在UPDATE/DELETE的查询过程中,可以和shared lock兼容,但是与其他U和X锁不兼容。
  3. 对数据进行修改的时候,U锁会升级成为X锁
  4. 一般情况下,我们讨论的lock是TRANSACTION lock,但除此之外,还有SHARED_TRANSACTION_WORKSPACE (Resource = DATABASE)、
    EXCLUSIVE_TRANSACTION_WORKSPACE (Resource = DATABASE)、游标锁、Session Locks (Resource = DATABASE)。
  5. 对于lock的粒度,可以是ROW(RID or KEY)、PAGE、TABLE、PARTITION、EXTENT、DATABASE
  6. SQL SERVER会在多层上放置lock。比如,修改一条记录,会在TABLE 和 PAGE上方式IX锁,在ROW上放置X锁
  7. sys.dm_tran_locks可以用来查看当前的所有lock
  8. ROW锁会升级为更高级别的锁。遇到过一个案例就是锁升级为page锁,进而导致deadlock。
0
Posted on Tuesday, September 13, 2016 by 醉·醉·鱼 and labeled under

拜读完 https://www.simple-talk.com/sql/t-sql-programming/row-versioning-concurrency-in-sql-server/,快快记录一些东西,方便以后回忆。
  1. READ_COMMITTED_SNAPSHOT 和 SNAPSHOT都是基于snapshot的隔离级别
  2. 两种机制都会复制数据一个version到tempdb
  3. 在物理存储上,每条数据都会增加长度为14bytes的pointer和XSN
  4. pointer会指向之前的version,之前的version又会指向更早的version,直到最早的version。有点想HEAP里出现page split一样。
  5. SNAPSHOT机制减少了lock,增加了tempdb开销,间接增加UPDATE和DELETE的代价
  6. READ_COMMITTED_SNAPSHOT 可以避免脏读。是statement level的snapshot isolation。第二次读是可以读到另外TRAN里提交的改动。
  7. SNAPSHOT 可以避免脏读,不可重复读和幻读。是transaction level的snapshot isolation。第二次读到的和第一次读到的一致。
  8. 由于基于version,reader和writer互不block,但是writer还是会block writer。
  9. 正是由于SNAPSHOT可以重复读,会导致UPDATE CONFLICT。即UPDATE的时候其他session已经提交了改动,这个时候就会UPDATE CONFLICT。
  10. 开启READ_COMMITTED_SNAPSHOT需要关闭所有ACTIVE SESSION。
  11. 开启READ_COMMITTED_SNAPSHOT需要将代码里面的NOLOCK抹掉,并默认为READ COMMITTED隔离级别。
0
Posted on Tuesday, September 13, 2016 by 醉·醉·鱼 and labeled under
项目是用SQLCMD加载文件进行schema部署的,如果部署中间出问题了,会是部分提交,还是全部回滚呢?

创建下面的文件

PRINT 'YES'
GO
update test
set someValue = 987
where id = 1
GO
THROW 51000, 'The record does not exist.', 1;  
GO
PRINT 'YES AGAIN'
GO

测试

sqlcmd -S .\MSSQLSERVER2012 -d event_service -i ./sqlcmd_test.sql -m-1 -r -I -b

结果是,部分提交,和你在SSMS里面一样,即使你加了-b option。