https://qiita.com/jonson29/items/4743409eda08fcdf5410

論理削除と物理削除とは

この記事は最終更新日から1年以上が経過しています。

論理削除とは

実際にはデータを削除せずに、削除されたと見なすフラッグと呼ばれるカラムを設定することでユーザーには削除しているかのように振る舞うことができることをさします。

例えばtweetsテーブルというものがあった時に、
そのテーブルにdeleted_flagというboolean型のカラムを追加しておきます。
この状態のときdeleted_flagカラムのデフォルト値はnullです。
こうすることによって、ユーザーにtweetの削除ボタンが押された時にdeleted_flagに1という値がセットすることで、その削除されたツイートとして扱うことができるのです。

物理削除

実際にSQLでDeleteされることをさし、データベースからも削除されます。そのため復元したり削除されたデータを参照することはできません。

論理削除のメリット

先ほどの例でも伝えたとうり、削除したかのように振る舞うだけなのですぐにデータの復元を実現が可能となります。また物理削除に比べても処理速度が早いことがメリットです。

論理削除のデメリット

・データベースにNUllというデータを作りたくない。(これはどうにかしたら解決可能だとは思いますが)
・where句での絞り込み検索を行うときにフラッグの条件を追加する必要がある。


PostgreSQL에서 Bulk Upsert

PostgreSQL 9.5에서 ON CONFLICT 가 도입된 후 Upsert (Insert or Update) 문을 쓸수 있게 되었지만、복수행을 bulk로 보내는건 불가했다.

ON CONFLICT 를 사용하지 않아도、CTE 로 로직을 만들어 Bulk Upsert 와 같은 결과를 내는 것이 가능하다.

WITH
-- write the new values
n(ip,visits,clicks) AS (
  VALUES ('192.168.1.1',2,12),
         ('192.168.1.2',6,18),
         ('192.168.1.3',3,4)
),
-- update existing rows
upsert AS (
  UPDATE page_views o
  SET visits=n.visits, clicks=n.clicks
  FROM n WHERE o.ip = n.ip
  RETURNING o.ip
)
-- insert missing rows
INSERT INTO page_views (ip,visits,clicks)
SELECT n.ip, n.visits, n.clicks FROM n
WHERE n.ip NOT IN (
  SELECT ip FROM upsert
)

[위 sql 출처](Faster data updates with CartoDB — CARTO Blog)

주의점

select문과 update, insert 문과의 차이점은 select문은 복수행을 한번에 취득한다는 점이고, update, insert 문은 row by row로 결과를 취득한다는 것이다. 때문에 위의 UPDATE문에서 n테이블을 사용했을 때, 마치 for loop 도는 것과 같은 액션이 가능한 것


In SQL, a join is used to compare and combine — literally join — and return specific rows of data from two or more tables in a database. An inner join finds and returns matching data from tables, while an outer join finds and returns matching data and some dissimilar data from tables.



Inner Join

An inner join focuses on the commonality between two tables. When using an inner join, there must be at least some matching data between two (or more) tables that are being compared. An inner join searches tables for matching or overlapping data. Upon finding it, the inner join combines and returns the information into one new table.


Example of Inner Join

Let's consider a common scenario of two tables: product prices and quantities. The common information in the two tables is product name, so that is the logical column to join the tables on. There are some products that are common in the two tables; others are unique to one of the tables and don't have a match in the other table.

An inner join on Products returns information about only those products that are common in both tables.

Outer Join

An outer join returns a set of records (or rows) that include what an inner join would return but also includes other rows for which no corresponding match is found in the other table.

There are three types of outer joins:

  • Left Outer Join (or Left Join)
  • Right Outer Join (or Right Join)
  • Full Outer Join (or Full Join)

Each of these outer joins refers to the part of the data that is being compared, combined, and returned. Sometimes nulls will be produced in this process as some data is shared while other data is not.

Left Outer Join

A left outer join will return all the data in Table 1 and all the shared data (so, the inner part of the Venn diagram example), but only corresponding data from Table 2, which is the right join.

Left Join Example

In our example database, there are two products — oranges and tomatoes — on the 'left' (Prices table) that do not have a corresponding entry on the 'right' (Quantities table). In a left join, these rows are included in the result set with a NULL in the Quantity column. The other rows in the result are the same as the inner join.

Right Outer Join

A right outer join returns Table 2's data and all the shared data, but only corresponding data from Table 1, which is the left join.

Right Join Example

Similar to the left join example, the output of a right outer join includes all rows of the inner join and two rows — broccoli and squash — from the 'right' (Quantities table) that do not have matching entries on the left.

Full Outer Join

A full outer join, or full join, which is not supported by the popular MySQL database management system, combines and returns all data from two or more tables, regardless of whether there is shared information. Think of a full join as simply duplicating all the specified information, but in one table, rather than multiple tables. Where matching data is missing, nulls will be produced.

These are just the basics, but many things can be done with joins. There are even joins that can exclude other joins!

Video Explaining Inner vs Outer Joins

This video explains the difference between various types of joins. It is cued up to begin at the point where the discussion about joins begins.


'DataBase > SQL Basic' 카테고리의 다른 글

sql program diary  (0) 2019.06.17

https://limkydev.tistory.com/100?category=974039


[DataBase] 트랜잭션이란? (Transaction)

Limky Lim-Ky 2017. 10. 6. 02:22

트랜잭션(Transaction) 개념


C나 Java와 같은 프로그래밍 언어로 작성된 응용 프로그램은 명령어들의 집합으로 볼 수 있는데, 이러한 프로그램들은 세부적으로 여러 개의 함수나 클래스 단위로 구성됩니다. 함수나 클래스들은 전적으로 프로그래머가 프로그래밍의 편리성과 효율성 중심으로 설계한 결과물입니다. 

그러나 데이터베이스 응용프로그램에서는 프로그램의 구성을 다른 관점으로 살펴 볼 수 있습니다. 예를 들어 은행 업무에 관련된 데이터베이스 응용 프로그램을 가정해봅시다. 이 프로그램은 계좌이체, 대출, 예금, 출금 등과 같이 은행에서 이루어지는 여러 가지 업무처리에 관련된 세부 프로그램들로 구성됩니다. 이러한 세부 프로그램들은 사용자 입장에서 보면 하나의 작업 단위가 됩니다. 그리고 이러한 작업들을 수행하기 위해서는 세부적으로 여러가지의 데이터베이스에 대한 연산(검색, 삽입, 삭제, 수정)들을 필요로 합니다. 



예를 들어 A계좌에서 B계좌로 일정 금액을 이체한다고 가정해봅시다. 이를 위해서는 그림과 같이 A계좌의 잔액을 확인하고 현재 금액에서 인출할 금액을 뺀 나머지 금액을 다시 저장합니다. 그런 다음 B계좌의 잔액을 읽어 들인 후 이체된 금액을 더하고 그 합을 다시 저장하면 계좌이체가 완료됩니다. 이러한 과정들이 모두 합쳐져 계좌이체라는 하나의 작업단위를 구성합니다. 데이터베이스에서는 이와 같은 하나의 논리적인 작업 단위를 구성하는 연산들의 집합을 트랜잭션이라 합니다. 이러한 관점에서 데이터베이스 응용 프로그램은 트랜잭션들의 집합으로 정의 할 수 있습니다.





트랜잭션(Transaction) 필요성


트랜잭션을 정의하는 이유는 무엇일까요? 그 동안 알지 못했지만, 우리는 현실에서 트랜잭션을 간접적으로 경험하고 있습니다. 계좌이체를 다시 생각해봅시다. 많은 사람들이 현금 인출기에서 카드를 이용하여 계좌이체를 한 경험이 있을 것입니다. 이때 현금 인출기를 작동하는 도중에 기계오류나 정전 등과 같은 예기치 않은 상황이 발생하여 카드가 나오지 않거나 기계가 멈추는 경우가 있습니다. 이때 가장 우려되는 것이 내 계좌에서는 금액이 빠져나간 것으로 기록되고 정작 상대방 계좌에는 이체가 되지 않는 상황입니다. 트랜잭션이란 바로 이러한 문제가 발생되지 않도록 하는 강력한 수단을 제공해주는 것입니다. 즉, 내 계좌에서 금액이 빠져나가기 전 상태로 돌아가던지, 아니면 상대방 계좌로 이쳬가 성공적으로 끝나도록 보장해줘야 합니다. 


계좌이체 과정에서 발생 할 수 있는 문제점을 좀 더 구체적으로 알아보기 위해 그림을 다시 봅시다. 이 그림에서 A계좌에서 이체할 금액을 인출한 다음 B계좌에 이체된 금액을 저장하기 전에 어떠한 이유로 해서 실행이 중단되었다고 가정해봅시다. 즉, 그림에서 마지막 명령문 WRITE t 가 실행되지 않은 상황을 의미합니다. 그러면 A계좌에는 이미 잔액이 인출된 결과가 저장되었지만, B계좌는 변경이 되지 않은 채로 남아있게 됩니다. 은행 업무에서 이러한 결과는 결코 발생되면 안됩니다. 즉, 계좌이체를 실행 할 때는 계좌이체에 정의된 모든 연산을 완벽하게 실행하던지, 아니면 모두 실행하지 않고 처음의 상태로 남아있어야 합니다.


또 다른 예로 은행에서 현금을 인출하는 과정을 살펴보면, 은행에서 예금을 인출하는 작업은 다음과 같은 연산으로 이루어집니다.


1. 예금 잔액을 확인한다.

2. 해당 인출금을 잔액에서 뺀다.

3. 인출금을 뺀 나머지를 새로운 잔액으로 저장한다.

4. 인출금을 지급한다.





만약 현재 잔액이 500원인 계좌에 대해 두 사람이 각각 A지점과 B지점에서 동시에 100원을 인출하는 작업을 진행한다고 가정해 봅시다. 이 상황은 위 그림과 같습니다. 이 그림을 보면 우선 A와 B에서 예금 잔액을 읽고 동시에 그 값이 500원이라는 것을 확인 합니다. 다음 두 지점에서 각각 잔액 500원에서 100원을 뺍니다. 그러면 A와 B모두 잔액이 400으로 계산되어, 400원을 각각 저장합니다. 마지막으로 100원을 A와 b 모두에서 지급합니다. 결국 A와 B지점에서 각각 100원씩 인출하여, 결국 200원을 인출한 셈이 되고 잔액은 400원이 됩니다. 이 상황도 올바르지 못합니다. 이러한 오류의 원인은 A지점에서 잔액으로 400을 저장하였고, B지점에서도 400원을 저장함으로써, 둘 중 하나가 다른 지점에서 저장한 잔액을 덮어 써버렸기 때문입니다. 결국 다중 사용자 환경에서 하나의 트랜잭션이 동시에 실행되는 다른 트랜잭션에 의해 영향을 받은 결과입니다.


따라서 지금까지 예를 든 상황과 같이 원하지 않는 결과가 발생되지 않도록 사전에 방지하기 위해서 트랜잭션은 필요합니다. 현재 대부분의 DBMS들은 이러한 상황을 방지하기 위한 기능을 갖추고 있습니다. 이를 위해 데이터베이스 개발자는 작업 단위들을 트랜잭션으로 적절히 정의해야 합니다. 즉, 트랜잭션을 정의하는 것은 전적으로 개발자의 의무이지만, 정의된 트랜잭션들에 대해서 위와 같은 문제가 발생하지 못하게 방지하는 것은 DBMS의 몫입니다. 





트랜잭션(Transaction)의 특징(지켜야 할 조건)


지금까지 설명한 내용을 토대로 트랜잭션의 특징을 정리해보겠습니다. 중요한 개념이기 때문에 꼭 암기해서 외워야합니다. DBMS는 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability) 이 만족해야 합니다. 

다음 조건들의 영어 첫 단어를 인용해 ACID 특성(ACID property)라고 합니다. 



  원자성(Atomicity)

트랜잭션 실행 도중에 문제가 발생했을 경우, 중단된 상태가 아닌 모두 실패하거나, 모두 완성 둘 중 하나의 상태가 되어야 합니다. 즉 100개 명령어로 구성된 트랜잭션 중 99개 완료 1개 실패가 된다면, 이는 무조건 실패로 간주하여 트랜잭션 시작 전 상태로 돌려야 합니다. 또한, 100개 모두가 성공했을 시 트랜잭션은 성공합니다. 따라서 중간상태란 없습니다.  

 일관성(Consistency)

일관성이란 트랜잭션 완료 후에도 데이터베이스가 일관된 상태로 유지되어야 합니다. 예를 들어 계좌이체를 성공적으로 실행했다면, A계좌의 잔액과 B계좌의 잔액의 합이 트랜잭션 실행 전의 합과 동일해야 합니다.  

 고립성(Isolation)

고립성이란 하나의 트랜잭션이 실행하는 도중에 변경한 데이터는 이 트랜잭션이 완료될 때까지 다른 트랜잭션이 참조하지 못하게 하는 특성입니다. 하나의 트랜잭션이 A라는 계좌에서 작업을 하고 있다면, 다른 트랜잭션이 A계좌에 대해 참조하거나 관여 할 수 없고 작업이 끝날 때까지 대기하거나 해야합니다. 

 지속성(Durability

지속성은 트랜잭션이 완료되면, 주기억장치가 아닌 디스크와 같은 보조기억장치에 저장되거나 그렇지 않더라도 시스템 장애가 회복되고 난 후에 어떠한 형태로든지 그 데이터를 복구 할 수 있게 해야함을 뜻합니다.  






트랜잭션(Transaction)의 상태



이제 앞서 설명했던 트랜잭션이 갖추어야 할 조건들 ACID 특성을 충족시키기 위해선 트랜잭션이 현재 어떤 상태인지 정의할 필요가 있습니다. 이에 따라 트랜잭션 각 상태에 따라 어떤 상황인지 알아봅시다. 




Active(활동)

트랜잭션이 실행 중에 있는 상태, 연산들이 정상적으로 실행 중인 상태

Failed(장애)

트랜잭션이 실행에 오류가 발생하여 중단된 상태 

Aborted(철회) 

트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태 

Partially Committed(부분 완료)

트랜잭션이 마지막 연산까지 실행했지만, Commit 연산이 실행되기 직전의 상태 

Committed(완료) 

트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태 



https://limkydev.tistory.com/108

[DataBase] 키(Key)의 개념 및 종류

데이터 베이스 키(Key)의 개념 및 종류**

키(Key)는 데이터베이스에서 조건에 만족하는 튜플을 찾거나 순서대로 정렬할 때 다른 튜플들과 구별할 수 있는 유일한 기준이 되는 Attribute(속성)입니다.

*튜플 : 릴레이션을 구성하는 각각의 행, 속성의 모임으로 구성된다. 파일 구조에서는 레코드와 같은 개념, 튜플의 수 = 카디널리티(Cardinality) = 기수 = 대응수

<학생> 릴레이션**

학번 주민번호 성명 성별 
1001  810429-1231457김형석  
1002 800504-1546781 김현천  
1002 811216-2547842 류기선 여 
1003910322-1233445 홍영선 

<수강> 릴레이션

과목명 
1001 영어 
1001 전산 
1002 영어 
1003 수학 
1004 영어 
1004 전산 

1. 후보키 (Candidate Key)

* 릴레이션을 구성하는 속성들 중에서 튜플을유일하게 식별할 수 있는 속성들의 부분집합을 의미합니다.
*모든 릴레이션은 반드시 하나 이상의 후보키를 가져야합니다.
* 릴레이션에 있는 모든 튜플에 대해서유일성과 최소성을 만족시켜야합니다.
 
ex) <학생> 릴레이션에서 '학번'이나 '주민번호'는 다른 레코드를 유일하게 구별할 수 있는 기본키로 사용할 수 있으므로 후보키가 될 수 있습니다. 즉 기본키가 될 수 있는 키들을 후보키라고 합니다.

2. 기본키 (Primary Key)

* 후보키 중에서 선택한 주키(Main Key)
* 한 릴레이션에서특정 튜플을 유일하게 구별할 수 있는 속성* Null 값을 가질 수 없습니다. (개체 무결성의 첫번째 조건)
* 기본키로 정의된 속성에는 동일한 값이 중복되어 저장될 수 없습니다.(개체 무결성의 두번째 조건)
 
ex) <학생> 릴레이션에는 '학번'이나 '주민번호'가 기본키가 될 수 있고, <수강> 릴레이션에는 '학번'+'과목명'으로 조합해야 기본키가 만들어 질 수 있습니다. 왜냐면 <수강> 릴레이션에서는 '학번' 속성과 '과목명' 속성은 개별적으로 기본키로 사용할 수 없습니다. 다른 튜플들과 구별되지 않기 때문이지요..
ex) <학생> 릴레이션에서 '학번'을 기본키로 정의되면 이미 입력된 '1001'은 다른 튜플의 '학번' 속성 값으로 입력할 수 없습니다.

3. 대체키 (Alternate Key)

*후보키가 둘 이상일 때 기본키를 제외한 나머지 후보키들을 말합니다.* 보조키라고도 합니다.
 
ex) <학생> 릴레이션에서 '학번'을 기본키로 정의하면 '주민번호'는 대체키가 됩니다.

4. 슈퍼키 (Super Key)

*슈퍼키는 한 릴레이션 내에 있는 속성들의 집합**으로 구성된 키로서 릴레이션을 구성하는 모든 튜플 중 슈퍼키로 구성된 속성의 집합과 동일한 값은 나타내지 않습니다.
* 릴레이션을 구성하는 모든 튜플에 대해
유일성은 만족하지만, 최소성은 만족시키지 못합니다.**
 
ex) <학생> 릴레이션에서는 '학번', '주민번호', '학번'+'주민번호', '학번'+'주민번호'+'성명' 등으로 슈퍼키를 구성할 수 있습니다. 또한 여기서 최소성을 만족시키지 못한다는 말은 '학번'+'주민번호'+'성명' 가 슈퍼기인 경우 3개의 속성 조합을 통해 다른 튜플과 구별이 가능하지만, '성명' 단독적으로 슈퍼키를 사용했을 때는 구별이 가능하지 않기 때문에 최소성을 만족시키지 못합니다. 즉 뭉쳤을 경우 유일성이 생기고, 흩어지면 몇몇 속성들은 독단적으로 유일성있는 키로 사용할 수 없습니다. 이것을 최소성을 만족하지 못한다고 합니다.

5. 외래키 (Foreign Key)

* 관계(Relation)를 맺고 있는 릴레이션 R1, R2에서 릴레이션 R1이 참조하고 있는 릴레이션 R2의 기본키와 같은 R1 릴레이션의 속성
* 외래키는참조되는 릴레이션의 기본키와 대응되어 릴레이션 간에 참조 관계를 표현하는데 중요한 도구로 사용됩니다.
**외래키로 지정되면 참조 테이블의 기본키에 없는 값은 입력할 수 없습니다. *(참조 무결성 조건)
 
ex) <수강> 릴레이션이 <학생> 릴레이션을 참조하고 있으므로 <학생> 릴레이션의 '학번'은 기본키이고, <수강> 릴레이션의 '학번'은 외래키입니다. 즉 각 릴레이션의 입장에서 속성은 기본키가 되기도하고, 외래키가 되기도 합니다.
ex) <수강> 릴레이션의 '학번'에는 <학생> 릴레이션의 '학번'에 없는 값은 입력할 수 없습니다.

▶ join사용하지 않고 windows함수를 사용해 max_date 셀렉트하기

  

SELECT group,MAX(date) as max_date
FROM table
WHERE checks>0
GROUP BY group

That works to get the max date..join it back to your data to get the other columns:

Select group,max_date,checks
from table t
inner join 
(SELECT group,MAX(date) as max_date
FROM table
WHERE checks>0
GROUP BY group)a
on a.group = t.group and a.max_date = date

https://stackoverflow.com/questions/19432913/select-info-from-table-where-row-has-max-date



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul



▶ default

 defaul

















'DataBase > SQL Basic' 카테고리의 다른 글

Inner join, outer join, left join, right join  (0) 2020.02.19

title: SQL Serverのロックについて出来る限り分かりやすく解説
tags: SQL SQLServer ロック DB
author: maaaaaaaa

slide: false

#SQL Serverのロックとは
DB上でデータを操作(SELECT/INSERT/UPDATE/DELETE等)する際、データの整合性を保つために使われる排他制御の仕組み。
例えば、「1つのレコードを一度に更新できるのは、1つのクエリだけ」といったルールを実現してくれる。

#SQL Serverのロックを理解するための3つのポイント
1.ロックには複数の粒度(階層とも呼ばれる)が存在する
2.ロックには複数の種類が存在する(ロックモード)
3.各ロックモード間には「互換性」という関係性がある

以降で順を追って説明する。

#なぜロックについて知る必要があるのか
ロックはデータの整合性を保つために必要な仕組みだけど、ブロッキングの原因にもなりやすい。

そのため、クエリを実行する際に「どういったロックが、どの粒度でかけられるのか、そのロックの互換性はどうか」といったことを開発者が意識できるとブロッキングの発生を未然に防ぐ(または最小限に抑える)ことが可能となる。

ロックの粒度

ロックには粒度が存在する。ロックリソースとも呼ばれる。
MSのドキュメントには、ロックリソースの種類として以下の図が掲載されている。見方にポイントがあるので解説。

image.png


出典:https://docs.microsoft.com/ja-jp/sql/2014-toc/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-2014

###①RID~TABLE
SQL Serverのデータ構造と対応しており、階層構造になっている。
以下のようにKEY→PAGE→HoBT(Heap or BTree=Index)→TABLEの順番。KEYが最下層、TABLEが最上位。

image.png

※HoBT:Heap or B-Treeの略。
※EXTENT:物理的に連続した8ページをひとまとめにしてエクステントと呼ぶ。ページの効率的な管理のために使用される。

image.png

###②METADATA
統計情報の更新時などに獲得されるロックリソース。

###③DATABASE
最も粒度の大きいロックリソース。クエリを実行すると必ず該当DBにSロックをかける。
また、ALTER DATABASEの実行時などにこのリソースにUロック等が獲得される。

--互換性レベルの変更。該当DBにUロックをかける

ALTER DATABASE
SomeDataBase
SET COMPATIBILITY_LEVEL = 150

※ロック粒度についてのドキュメント
https://docs.microsoft.com/ja-jp/sql/2014-toc/sql-server-transaction-locking-and-row-versioning-guide?view=sql-server-2014

#ロックの種類
MSのドキュメントから、よく出てくるロックの種類(ロックモード)を抜粋。
ポイント:ロックにはいろいろな種類がある。発行するクエリによって、SQL Serverが自動的に必要なロックをかけてくれる。(各ロックの違いは後述)
ポイント:ロックの種類が異なるだけで、クエリを発行すると実は何らかのロックが必ず獲得されている。
ポイント:最低限覚えておくと良いのは、「SELECTはS、INSERT/UPDATE/DELETEはX、with(nolock)つきのSELECTはSch-S」

image.png


出典:https://docs.microsoft.com/ja-jp/previous-versions/sql/sql-server-2008-r2/ms175519%28v%3dsql.105%29

#ロックの互換性

###「互換性」とは
「同一のロックリソースに対して、同時に旗を立てることができるかどうか」とイメージすると分かりやすい。

###例:S Lock(共有ロック)同士
互換性があるため、同時に2つ以上のS Lockをかけることができる

image.png


クエリレベルだと、「次の二つのクエリは同時に実行できる」という意味。

image.png

###例:S Lock(共有ロック)とX Lock(排他ロック)
互換性が無いため、同時にかけられるロックは1つだけ。

image.png


既にS Lockをかけていた場合は、X Lockはかけられない。このとき、X Lockをかけるためにクエリが待ち状態になる。
→これが「ブロッキング」

クエリレベルだと、「次の二つのクエリは同時に実行できない」という意味。

image.png

逆も同様。既にX Lockをかけていた場合は、S Lockはかけられない。S Lockをかけるためにクエリが待ち状態になる。

image.png

###例:with(nolock)をつけたクエリの挙動
with(nolock)は、正確にはロックをかけないわけではなく、Sロックの代わりにSch-Sロック(スキーマ安定度ロック:Schema Stability Lock)という弱いロックをかけている。

image.png

クエリレベルだと、「次の二つのクエリは同時に実行できる」という意味。

image.png

ここはとても大事なところなので、Sch-SロックとSロックの図を並べて見比べてみる。

image.png

ポイント①:with(nolock)無しのSELECT文を長時間実行すると、取得したSロックによって更新処理(X Lock)をブロックしてしまう恐れがある
→データの読み取りしかできない権限であっても、長時間のSELECT文実行によってブロッキングを発生させる恐れがあるため気をつける

ポイント②:Sch-SロックはXロックと競合しない。その代わり、未コミットのデータを読み取れてしまうため、正しくない結果を読み取ってしまう恐れがある

※with(nolock)を全テーブルにつけたときと、「SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED」をクエリの前に書くことで得られる効果は同一。
※with(nolock) / READ UNCOMMITTEDトランザクション分離レベルによって影響を受けるのはSELECT文のみ。UPDATE/INSERT/DELETE等は挙動が変わらない。

###例:with(nolock)をつけてもブロッキングが発生するとき
どんなロックとも競合する最強のロックである、Sch-Mロック(スキーマ修正ロック:Schema Modification Lock)がかかっている状態だと、with(nolock)をつけたSELECT文でも互換性が無いためブロックされる。

image.png

クエリレベルだと、「次の二つのクエリは同時に実行できない」という意味。

image.png

###例:1つのクエリが、同一リソースに複数ロックをかけるケース
update文を実行すると、レコードに対してUロックとXロックが取得される。おそらくUロックを獲得した後にXロックへと昇格させていると思われる。

image.png

 

image.png

###ロックモードの互換性
MSのドキュメントにある以下の図を参照。

image.png

全ての互換性を示した図は以下の通り。↑の互換性の加えて、Sch-S / Sch-Mロックのみ押さえておけばとりあえずはOK。

image.png


出典:https://docs.microsoft.com/ja-jp/previous-versions/sql/sql-server-2008-r2/ms186396(v=sql.105)

#ロックの種類と粒度と互換性について理解する

###ポイント:同一粒度の同一リソースには、互換性が無いロックは同時にかけられない

image.png

###ポイント:同一粒度の別リソースには、互換性が無いロックを同時にかけられる

image.png

###ポイント:粒度が異なるロック
上位の階層に互換性の無いロックがかかっていると、下位のリソースに対してロックをかけられない

image.png

###ポイント:インテントロックについて理解する
レコードにXロックをかける場合、その上位階層であるPAGEとTABLEに対して、IXロック(インテントXロック)が自動でかけられる。
理由は、排他制御の処理効率アップのため。
もしIXロックがなければ、例えば他のクエリがテーブル全体にXロックをかけたいときに、全ページと全レコードに互換性の無いロックがかかっていないか調べる必要がある。
一方、テーブルにIXロックがあると、それだけでテーブルにXロックをかけられないことが分かるため、ロックの可否の判断効率が良い。

image.png

先ほどの「上位の階層に互換性の無いロックがかかっていると、下位のリソースに対してロックをかけられない」というルールは、
インテントロックを用いると以下のように説明できる。
「TABLEに対してXロックを獲得している場合は、TABLEへのIXロックが互換性が無いためブロッキングされる」

image.png

###ポイント:ロックの種類、対象の粒度などはすべてSQL Serverが自動的に決めてやってくれる
→ある程度なら意図的に粒度をいじることもできるが、基本的にはSQL ServerにまかせておけばOK。

#ロックの保持期間
ロックを保持する期間は、「明示的にトランザクションを開始しているかどうか」で変わる。

###明示的なトランザクション(begin tran - commit tran)を使わない場合
クエリ実行直後にロックを開放。

image.png

###明示的なトランザクションを使う場合
Sロック:クエリ実行直後にロックを開放。(既定のトランザクション分離レベルである「Read Committed」の場合の挙動)
Uロック / Xロック:クエリの開始からトランザクションのコミット又はロールバックが完了するまでロックを保持する。
イメージ図は以下の通り。

image.png

###ブロッキングを最小限に留めるコツ
トランザクションを張っている期間は必要最小限に留め、可能な限り短くする。(コード量の観点からも、実行時間の観点からも)
例:要件的に許されるのであれば、SELECT文をトランザクションの外に出すことで、TableBのロック保持期間を短縮できる。

image.png

#ロックエスカレーション

例えばテーブルの全レコードを更新する際、1レコードずつにXロックをかけるより、テーブルに1つだけXロックをかけてしまったほうが効率が良い。※1ロックあたり、粒度に関係なくメモリを96Bytes消費するためメモリリソースの観点からも効率が良い。

https://docs.microsoft.com/ja-jp/sql/database-engine/configure-windows/configure-the-locks-server-configuration-option?view=sql-server-2017

image.png


このように、大量のPAGEやKEYにロックをかける場合に、SQL Serverが自動的にロックの粒度をTABLEに昇格する場合がある。
この挙動をロックエスカレーションという。

image.png


ロックエスカレーションが起きると、該当テーブルへの更新がすべてブロックされてしまうため注意が必要。

ポイント:エスカレーション先のリソースはテーブルのみ。(KEY→PAGEといったエスカレーションは無い。必ずKEY→TABLEやPAGE→TABLEとなる。)

#デッドロック
下図において、①から④の順番でクエリが実行されるとすると、

①プロセスAがテーブルAのKEYロックを取得
②プロセスBがテーブルBのKEYロックを取得
③プロセスAがテーブルBのKEYロックを取得しようとするが、ブロッキングが発生。待ち状態になる。
④プロセスBがテーブルAのKEYロックを取得しようとするが、ブロッキングが発生。待ち状態になる。
 →この時点で、相互にブロックし合う関係になってしまい、このままだとプロセスA、プロセスB共に無限に待ち続けることに。これがデッドロック状態。

⑤数秒後、SQL Serverが自動でデッドロックを検出し、プロセスAまたはプロセスBのどちらかを強制終了し、デッドロックを解消。

image.png


ポイント:ブロッキングとデッドロックの違い
・「ブロッキング」は、blockerのクエリが終了しない限りwaiterのクエリは無限に待たされる。一方で、「デッドロック」は、SQL Serverが数秒間隔で自動検出して自動解消してくれる。
・「ブロッキング」は、SQL Serverの介入が無いためKILLしない限りblockerもwaiterも最終的には実行完了する。一方で、「デッドロック」は、クエリ実行中であっても片方のプロセスがSQL Serverによって強制終了される。

#クエリでブロッキングを検出

###検出クエリ
Microsoft MVPの小澤さんのgithubで公開されているクエリが素晴らしく便利。(そのまま実行してOK)
https://raw.githubusercontent.com/MasayukiOzawa/SQLServer-Util/master/Lock/%E3%83%96%E3%83%AD%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E3%83%81%E3%82%A7%E3%83%BC%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97.sql

ブロッキングが起きている場合は、以下のような情報が取得できる。

image.png

さらに、HeadBlockerのspid(プロセスID)を使って、一連のブロッキングの元凶となっているクエリの詳細情報を取得できる。

dbcc inputbuffer(70)
go
sp_who2 70

↓のように、クエリテキストやホスト名などが分かる。

image.png

###現在実行中のクエリリストからも、ブロッキングの発生が分かる

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
SELECT TOP 100
     der.session_id as spid
    ,der.blocking_session_id as blk_spid
    ,datediff(s, der.start_time, GETDATE()) as elapsed_sec
    ,DB_NAME(der.database_id) AS db_name
    ,des.host_name
    ,des.program_name
    ,der.status -- Status of the request. (background / running / runnable / sleeping / suspended)
    ,dest.text as command_text
    ,REPLACE(REPLACE(REPLACE(SUBSTRING(dest.text, 
    (der.statement_start_offset / 2) + 1, 
    ((CASE der.statement_end_offset
    WHEN -1 THEN DATALENGTH(dest.text)
    ELSE der.statement_end_offset
    END - der.statement_start_offset) / 2) + 1),CHAR(13), ' '), CHAR(10), ' '), CHAR(9), ' ') AS current_running_stmt
    ,datediff(s, der.start_time, GETDATE()) as time_sec
    ,wait_resource --ロックされているリソース名
    ,wait_type
    ,last_wait_type --最後または現在の待機の種類の名前
    ,der.wait_time  as wait_time_ms
    ,der.open_transaction_count
    ,der.command
    ,der.percent_complete --一部コマンドの進捗状況を表示してくれるらしい
    ,der.cpu_time
    ,(case der.transaction_isolation_level
      when 0 then 'Unspecified'
      when 1 then 'ReadUncomitted'
      when 2 then 'ReadCommitted'
      when 3 then 'Repeatable'
      when 4 then 'Serializable'
      when 5 then 'Snapshot'
    else cast(der.transaction_isolation_level as varchar) end) as transaction_isolation_level
    ,der.granted_query_memory * 8 as granted_query_memory_kb --キロバイト単位
--    ,deqp.query_plan -- 実行プラン
--  ,datediff(s, der.start_time, GETDATE()) / 60.0 as time_min
--  ,des.login_time
--  ,(select top (1) waitresource from  master.dbo.sysprocesses where spid = der.session_id) as waitresource
--  ,(select top (1) lastwaittype from  master.dbo.sysprocesses where spid = der.session_id) as lastwaittype
FROM
    sys.dm_exec_requests der
--JOIN sys.dm_exec_connections dec ON der.connection_id = dec.connection_id
JOIN sys.dm_exec_sessions des ON des.session_id = der.session_id
OUTER APPLY sys.dm_exec_sql_text(sql_handle) AS dest
--OUTER APPLY sys.dm_exec_query_plan(plan_handle) AS deqp
WHERE
    des.is_user_process = 1
AND datediff(s, der.start_time, GETDATE()) >= 1 -- 例:1秒以上実行中のクエリに限定
--AND dest.text like '%%' -- クエリの中身でlike検索したいときはここを編集
ORDER BY
    datediff(s, der.start_time, GETDATE()) DESC

↓のように、blk_spidに0以外の数字が表示される場合は、そのプロセスIDのクエリによってブロックされていると判断できる。

image.png

#まとめ
ロックの粒度、種類、互換性について解説した。
それぞれについて完全に覚えておく必要は無いけど、「XロックとSロックに互換性がないから、UPDATEの実行中は該当レコードへのSELECTはブロックされるのだろうな。データの大量更新を実行するタイミングはブロッキングが起きていないかDMVを使ってチェックしよう」
というように今回の内容を業務で使用するクエリレベルの話に自分で変換して考えられるようになると、ブロッキングなどのトラブルの軽減につながると思う。

SQL


SQL(Structured Query Language)은 RDB(Relational Database)에서 데이터베이스에 질의, 수정, 삭제 등의 작업을 하는 언어의 표준으로 채택되어 어떤 제품이든지 약간의 문법적 차이를 제외하고는 대동소이하며, 따라서, 오라클에서 사용하는 문법과 MS-SQL의 문법은 큰 차이가 없습니다.

 

SQL이란

 - SQL(Structured Query Language)은 RDB(Relational Database)에서 데이터베이스에 질의, 수정, 삭제 등의 작업을 하는 언어의 표준으로 채택되어 어떤 제품이든지 약간의 문법적 차이를 제외하고는 대동소이하며, 따라서, 오라클에서 사용하는 문법과 MS-SQL의 문법은 큰 차이가 없습니다. 

 

SQL문장 종류

 명령어 분류

 명령어

 설 명

 DQL

 Data Query Language

 (질의어)

 SELECT

 데이터 검색시 사용한다.

 DML

 Data Manipulation Language 

 (데이터 조작어)

 INSERT

 데이터 입력시 사용한다.

 UPDATE

 데이터 입력시 사용한다.

 DELETE

 데이터 입력시 사용한다.

 DDL

 Data Definition Language 

 (데이터 정의어)

 CREATE

 데이터베이스 객체 생성한다.

 ALTER

 데이터베이스 객체 변경한다.

 DROP

 데이터베이스 객체 삭제한다.

 RENAME

 데이터베이스 객체 이름 변경한다.

 TRUNCATE

 데이터베이스 객체의 저장 공간 삭제한다.

 TCL

 Transaction Control Language 

 (트랜잭션 처리어) 

 COMMIT

 트랜젝션의 정상적인 종료 처리한다.

 ROLLBACK

 트랜잭션 취소한다.

 SAVEPOINT

 트랜잭션내에 임시 저장점 설정한다.

 DCL

 Data Control Language 

 (데이터 제어어)

 GRANT

 데이터베이스에 대한 일련의 권한 부여한다.

 REVOKE

 데이터베이스에 대한 일련의 권한 취소한다.

+ Recent posts