當前位置:首頁 » 編程語言 » sql生成唯一

sql生成唯一

發布時間: 2025-01-16 18:35:25

Ⅰ 如何產生唯一的server id

我們都知道Mysql用server-id來唯一的標識某個資料庫實例,並在鏈式或雙主復制結構中用它來避免sql語句的無限循環。這篇文章分享下我對server-id的理解,然後比較和權衡生成唯一server-id的幾種方式。
server_id的用途
簡單說來,server_id有兩個用途:
1. 用來標記binlog event的源產地,就是SQL語句最開始源自於哪裡。
2. 用於IO_thread對主庫binlog的過濾。如果沒有設置 replicate-same-server-id=1 ,那麼當從庫的io_thread發現event的源與自己的server-id相同時,就會跳過該event,不把該event寫入到relay log中。從庫的sql_thread自然就不會執行該event。這在鏈式或雙主結構中可以避免sql語句的無限循環。
注意:相同server-id的event在io_thread這一層就過濾了;而對於replicate-(do|ignore)-等規則,則是在sql_thread這一層過濾的。io_thread和sql_thread都有過濾的功能。
server_id為何不能重復
在同一個集群中,server-id一旦重復,可能引發一些詭異問題。
看看下面兩種情況:
圖1:主庫與從庫的server-id不同,但是兩個或多個從庫的server-id相同
這種情況下復制會左右搖擺。當兩個從庫的server-id相同時,如果從庫1已經連接上主庫,此時從庫2也需要連接到主庫,發現之前有server-id相同的連接,就會先注銷該連接,然後重新注冊。
參考下面的代碼片段:
repl_failsafe (register_slave) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int register_slave(THD* thd, uchar* packet, uint packet_length)
{
int res;
SLAVE_INFO *si;
...
if (!(si->master_id= uint4korr(p)))
si->master_id= server_id;
si->thd= thd;
pthread_mutex_lock(&LOCK_slave_list);
/* 先注銷相同server-id的連接*/
unregister_slave(thd,0,0);
/* 重新注冊*/
res= my_hash_insert(&slave_list, (uchar*) si);
pthread_mutex_unlock(&LOCK_slave_list);
return res;
...
}

兩台從庫不停的注冊,不停的注銷,會產生很多relay log文件,查看從庫狀態會看到relay log文件名不停改變,從庫的復制狀態一會是yes一會是正在連接中。
圖2:鏈式或雙主結構中,主庫與從庫的server-id相同
從庫1同時又是relay資料庫,它能正確同步,然後把relay-log內容重寫到自己的binlog中。當server-id為100的從庫2 io線程獲取binlog時,發現所有內容都是源自於自己,就會丟棄這些event。因此從庫2無法正確同步主庫的數據。只有直接寫relay server的event能正確同步到從庫2。
上面兩種情況可以看到,在同一個replication set中,保持server-id的唯一性非常重要。
server_id的動態修改
無意中發現 server-id 竟然是可以動態修改的,可別高興的太早。好處是,上面圖1的情況下,直接修改其中一個從庫的server-id就可以解決server-id沖突的問題。壞處很隱蔽,如下圖的結構:

現在假設active-master因為某種原因與passive-master的同步斷開後,passive-master上進行了一些ddl變更。然後某dba突發奇想把passive-master的server-id修改為400。當雙master的復制啟動後,那些之前在passive-master上執行的server-id為200的ddl變更,會從此陷入死循環。如果是 alter table t engine=innodb ,它會一直不停,可能你會發現。但是像 update a=a+1; 這樣的sql,你很難發現。當然這種場景只是我的杜撰,這兒有個更真實的例子 主備備的兩個備機轉為雙master時出現的詭異slave lag問題 。
舉這兩個例子只是想說明修改server-id有點危險,最好不要去修改,那麼能一步到位生成它嗎?
如何生成唯一的server_id
常用的方法有如下幾種:
1. 採用隨機數
mysql的server-id是4位元組整數,范圍從0-4294967295,因此採用該范圍內的隨機數來作為server-id產生沖突的可能性是非常小的。
2. 採用時間戳
直接用date +%s來生成server-id。一天86400秒來計算,往後計算50年,最大的server-id也才使用到86400*365*50,完全在server-id范圍內。
3. 採用ip地址+埠
這是我們經常採用的方法。例如ip為192.168.122.23,埠為3309,那麼server-id可以寫為122233309。產生沖突的可能性比較小:遇到*.*.122.23 或者*.*.12.223,而且搭建了同一個replication set的3309才會出現。
4. 採用集中的發號器
在管理伺服器上採用自增的id來統一分配server-id。這可以保證不沖突,但是需要維護中心節點。
5. 分開管理每個replication set
在每個replication set中為mysql庫增加一個管理表,保證每個從庫的server-id不沖突。
哪一種更好
上面的幾種方法都不賴,但是:
1. 方法4加了維護負擔,而且開發環境、測試環境、線上環境都維護一套發號器的話,有點麻煩,混在一起又可能遇到網段隔離的風險,還有發號器資料庫許可權的問題難於控制。所以不推薦。
2. 方法5實現了自治,但是管理成本有點高。從庫要能夠寫主庫的server-id表,復雜。
3. 5種方法都存在的問題是,使用冷備的數據來擴容,server-id需要手動去修改,否則就與冷備源的server-id沖突。而且,當mysql啟動的時候,你無法判斷該mysql是剛通過備份擴容的,還是之前一直正常運行的。所以你不知道這個server-id到底要不要改。而我希望server-id對dba完全透明,又絕不產生沖突,即可徹底屏蔽這個討厭的東西。
建議的方法
其實很簡單。ipv4是4位元組的整數,與server-id的范圍完全一樣。我們認為只有ip地址+埠才能唯一的確定一個mysql實例,所以總是希望把ip信息和埠信息都集成到server-id中。但是別忘了,一個ip上不能同時啟動兩個一樣的埠。所以,server-id只需採用ip地址的整數形式!自定義的mysql啟動腳本強制對server-id進行檢查,發現server-id不對就進行糾正,然後啟動。上面所有的問題,都會迎刃而解。

Ⅱ SQL Server唯一索引和非唯一索引的區別簡析

SQL Server創建索引時,可以指定Unique使之成為唯一索引。「唯一」顧名思義,但是兩都到底有什麼區別呢?因為索引也是一種物理結構,所以還是要從存儲和結構上分析。

索引結構分葉級和非葉級,分析時我們要分開來看,這個很重要。

文中涉及的索引行大小計算,參考MSDN估計資料庫大小索引部分。

1. 非唯一聚集索引和唯一聚集索引

創建兩個測試表,各10000條整數,tb1唯一,tb2非唯一,有1000條為9999的重復值。

view sourceprint?

01.<img onclick="this.style.display='none'; document.getElementById('Code_Closed_Text_402704').style.display='none'; document.getElementById('Code_Open_Image_402704').style.display='inline'; document.getElementById('Code_Open_Text_402704').style.display='inline';"id="Code_Closed_Image_402704"align="top"src=""width="11"height="16"style="display: none;"><img alt="載入中..."title="圖片載入中..."src="http://www.it165.net/statics/images/s_nopic.gif"><img onclick="this.style.display='none'; document.getElementById('Code_Open_Text_402704').style.display='none'; getElementById('Code_Closed_Image_402704').style.display='inline'; getElementById('Code_Closed_Text_402704').style.display='inline';"id="Code_Open_Image_402704"style="display: none;"align="top"src=""width="11"height="16"><img alt="載入中..."title="圖片載入中..."src="http://www.it165.net/statics/images/s_nopic.gif">Codecreate table tb1

02.(col1int);

03.declare@iint=1

04.while@i<10001

05.begin

06.insert into tb1 values(@i);

07.set@i=@i+1;

08.end;

09.create unique clustered index ucix on tb1 (col1)

10.go

11.-------

12.create table tb2

13.(col2int);

14.declare@iint=1

15.while@i<9001

16.begin

17.insert into tb2 values(@i);

18.set@i=@i+1;

19.end;

20.go

21.insert into tb2 values(9999)

22.go1000;

23.create clustered index cix on tb2 (col2)

24.go

先查詢索引的一些基本狀況:

發現多出一個UNIQUIFIER,同樣葉級也是一樣。MSDN說明:

「如果聚集索引不是唯一的索引,SQL Server 將添加在內部生成的值(稱為唯一值)以使所有重復鍵唯一。此四位元組的值對於用戶不可見。僅當需要使聚集鍵唯一以用於非聚集索引中時,才添加該值。」

還有UNIQUIFIER不是一個全局自增列,重復記錄增加時此值會發生改變,並且它是一個可為null的變長列。

現在來算一算索引行大小:

兩個表都是只有一個int型可為NULL的欄位,而聚集索引葉級是存儲數據本身

葉級是一個4位元組的INT列,無變長列,加上3位元組的NULL點陣圖,再加上4位元組的行頭開銷:兩個表的葉級minSize =4+0+3+4=11

非葉級是一個4位元組的INT列,無變長列,加上3位元組的NULL點陣圖,加上1位元組的行頭開銷,再加6位元組的子頁指針:兩個表的非葉級minSize=4+0+3+1+6=14

tb1的索引行大小是一致的minSize=maxSize,因為它是唯一的。tb2的索引行大小不一致,有大有小,大的索引行是因為:a)不唯一 b)UNIQUIFIER

唯一標識列增加了2+1*2+4=8位元組開銷,tb2的min和max相差就是這8位元組。

tb2的葉級maxSize=4+8+3+4=19

tb2的非葉級maxSize=4+8+3+1+6=22

小結:非唯一聚集索引為保證索引鍵值唯一性,會生成UNIQUIFIER與鍵列一起組成索引鍵值。同時無論在葉級還是非葉頁級,都比唯一索引佔用更多存儲空間。

Ⅲ sql newid()生成的guid唯一標示是如何保證他不重復

GUID的生成過程會參考當前時間,當前的硬體以及一些隨機數,來保證任何時間內任何機器都不會產生同樣的GUID

熱點內容
編程好軟體 發布:2025-01-16 20:38:07 瀏覽:423
流量密碼如何改成 發布:2025-01-16 20:37:13 瀏覽:49
java判斷是否是對象 發布:2025-01-16 20:31:04 瀏覽:885
python調用外部程序 發布:2025-01-16 20:14:09 瀏覽:397
緩解壓力英語作文 發布:2025-01-16 20:13:31 瀏覽:65
javaname 發布:2025-01-16 20:13:15 瀏覽:22
用戶訪問表空間 發布:2025-01-16 20:07:07 瀏覽:943
java代碼自動編譯 發布:2025-01-16 19:58:14 瀏覽:314
編程很困難 發布:2025-01-16 19:58:09 瀏覽:674
gg登錄源碼 發布:2025-01-16 19:58:07 瀏覽:293