【数据库设计】“Max加一”生成主键的注意点
Sql Server数据库的主键设计有多种,比如经典的自增长,欢乐的guid,按照时间生成id(有通过程序生成的方式,还有一种也是通过数据库时间和随机数生成),按照业务模型组合生成有意义的id等等。最近项目中接触到一种模拟自增长自动编号主键的方式,即Max加一
Sql Server数据库的主键设计有多种,比如经典的自增长,欢乐的guid,按照时间生成id(有通过程序生成的方式,还有一种也是通过数据库时间和随机数生成),按照业务模型组合生成有意义的id等等。最近项目中接触到一种模拟自增长自动编号主键的方式,即“Max加一”。
Max加一的原理看上去和自增长是相似的,表的唯一主键也设计成数字型(如bigint)的,只是把自动增长去掉了(表设计器标识规范一栏,“是标识”的选项选择否即可)。在Insert记录的时候,通常情况下的流程大致是这样的:读取当前表的Max主键值后加一,然后按照传递的相关参数,显式插入主键及其他列的值。这种生成主键方式的一个最显著的优点是可以按照自己的规则生成主键。比如有如下生成主键的用户自定义的存储过程usp_GetNewID:
<span>if</span> <span>exists</span> (<span>select</span> * <span>from</span> dbo.sysobjects <span>where</span> id = object_id(N<span>'[dbo].usp_GetNewID'</span>) <span>and</span> OBJECTPROPERTY(id, N<span>'IsProcedure'</span>) = 1) <span>drop</span> <span>procedure</span> [dbo].usp_GetNewID <span>GO</span> <span>CREATE</span> <span>PROCEDURE</span> [dbo].usp_GetNewID @tableName nvarchar(30), --表名 @columnName nvarchar(30), --字段名 @NewId <span>int</span> <span>output</span> --<span>Max</span>(ID)生成的新ID <span>AS</span> <span>BEGIN</span> <span>DECLARE</span> @MaxId bigint <span>DECLARE</span> @MaxIdTemp bigint <span>DECLARE</span> @<span>SQL</span> nvarchar(500) <span>DECLARE</span> @SQLDBId nvarchar(8) <span>set</span> @SQLDBId=<span>'10'</span> --获取原最大ID <span>set</span> @<span>SQL</span> =<span>'SELECT @Mymaxid= isnull(MAX('</span>+@columnName+<span>'),101) From '</span>+ @tableName; <span>-- select @MaxId </span> <span>if</span> @@error=0 <span>begin</span> <span>exec</span> sp_executesql @<span>SQL</span>,N<span>'@Mymaxid bigint output'</span>,@MaxId <span>output</span> <span>end</span> --生成新ID <span>if</span> @@error=0 <span>begin</span> <span>select</span> @MaxIdTemp=<span>SUBSTRING</span>(<span>cast</span>(@MaxId <span>as</span> nvarchar),3,100)+1; <span>end</span> <span>if</span> @@error=0 <span>begin</span> <span>set</span> @NewId=@SQLDBId+<span>cast</span>(@MaxIdTemp <span>as</span> nvarchar) <span>end</span> <span>else</span> <span>begin</span> <span>set</span> @NewId=-1 <span>end</span> END
通过将@SQLDBId='10'和set @NewId=@SQLDBId+cast(@MaxIdTemp as nvarchar)这种方式的组合,我们可以控制不同的数据库服务器(或者不同的库)生成的主键都有规律可循,比如第一台服务器生成的id都以10开头,第二台都以20开头,依此类推,这样多少有利于数据库的分布式管理。
下面简单说说这种方式的两个重大缺陷:
1、效率问题
虽然主键有聚集索引,但是当我们的数据表数据达到一定数量级的时候(比如千万),那么通过聚合函数Max取值肯定会有不小的代价,这样显然会影响一点效率。但是到底效率几何,和自增长的性能比较又如何?这个我真的还没有这方面的测试数据,如果有童鞋有这方面的经验请不吝赐教,恳求告知。
【UPDATE】:根据今天的性能测试,在表已有1百万数据基础上,继续插入数据,每次插入10000条记录,自增和Max加一这种方式的时间相差不足1秒,总体上自增长的方式会稍快一点,但是并不明显,在可接受范围内。测试结果见下图:
2、并发插入问题
当我们在程序中有顺序的先后插入数据的时候,这个问题当然不会发生。但是在大部分应用中,经常会并发处理一些数据,这个时候通过Max加一的方式就会造成插入上的并发问题。因为如果同时有两个或者多个插入请求读到相同的MAX值加一以后,在插入的时候就会发生插入重复主键的错误。
我们可以做一个简单的测试:
(1)、添加用户的存储过程usp_AddUser
<span>if</span> <span>exists</span> (<span>select</span> * <span>from</span> dbo.sysobjects <span>where</span> id = object_id(N<span>'[dbo].usp_AddUser'</span>) <span>and</span> OBJECTPROPERTY(id, N<span>'IsProcedure'</span>) = 1) <span>drop</span> <span>procedure</span> [dbo].usp_AddUser <span>GO</span> <span>CREATE</span> <span>PROCEDURE</span> [dbo].usp_AddUser <span>AS</span> <span>BEGIN</span> <span>DECLARE</span> @Id bigint <span>EXEC</span> usp_GetNewID <span>'Users'</span>,<span>'Id'</span>,@Id <span>OUT</span> <span>SELECT</span> @Id <span>if</span> @@ERROR=0 <span>BEGIN</span> INSERT <span>INTO</span> Users ( Id, Name ) <span>VALUES</span> ( @Id, <span>'jeff wong'</span> ) <span>END</span> END
用户表简单设计成有Id和Name两个字段,插入的时候,Name的值不受任何干扰,固定为”jeff wong”。
(2)、然后在应用程序中调用如下:
<span>static</span> <span>void</span> Main(<span>string</span>[] args) { <span>int</span> counter = 2000; Action action = <span>null</span>; <span>for</span> (<span>int</span> i = 0; i { Action method = a.AsyncState <span>as</span> Action; method.EndInvoke(a); }, action); } Console.Read(); } <span>private</span> <span>static</span> <span>void</span> AddUser() { <span>try</span> { <span>using</span> (var conn = <span>new</span> SqlConnection(sqlConnString)) { SqlCommand cmd = <span>new</span> SqlCommand(<span>"usp_AddUser"</span>, conn); cmd.CommandType = CommandType.StoredProcedure; conn.Open(); <span>int</span> result = cmd.ExecuteNonQuery(); } } <span>catch</span> (Exception ex) { Console.WriteLine(ex.ToString()); } }
在今晚本地的几组测试中,无一例外地都抛出了插入重复主键的异常。这个问题在这几天的一个数据同步程序中竟然没有发现,原因就是当时数据库没有或者很少符合条件的需要同步的数据。当然现在所有同步都已经改成通过在存储过程中利用游标顺序处理,这样就合理地解决掉并发插入问题了。
最后,我感觉主键的生成选择还有很多东西可以挖掘,有一些知识可以拿过来深入讨论一下,比如自增长是如何控制并发插入的,诸如此类,欢迎您的意见和建议。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











7월 12일 뉴스에 따르면, 새로운 Honor Vision Soothing Oasis 눈 보호 화면을 탑재한 Honor Magic V3 시리즈가 오늘 공식 출시되었습니다. 화면 자체는 높은 사양과 품질을 갖추고 있으면서도 AI 능동형 눈 보호 장치 도입을 개척했습니다. 기술. 근시를 완화하는 전통적인 방법은 근시 안경의 도수가 고르게 분포되어 있어 중심 시력 영역은 망막에 맺히지만 주변 영역은 망막 뒤에 맺히는 것으로 알려져 있습니다. 망막은 상이 뒤쳐져 있음을 감지하여 눈의 축방향 성장을 촉진시켜 정도를 심화시킵니다. 현재 근시 발생을 완화시키는 주요 방법 중 하나가 '디포커스 렌즈'다. 중심 영역은 정상적인 도수를 갖고, 주변 영역은 광학 설계 파티션을 통해 조절해 주변 영역의 상이 안으로 들어가게 한다. 망막 앞.

5월 13일 뉴스에 따르면 vivoX100s는 오늘 밤 공식적으로 출시되었으며 뛰어난 이미지 외에도 신호 성능도 매우 뛰어납니다. vivo의 공식 소개에 따르면 vivoX100s는 최대 21개의 안테나가 장착된 혁신적인 범용 신호 증폭 시스템을 사용합니다. 이 디자인은 5G, 4G, Wi-Fi, GPS, NFC 등 다양한 신호 요구 사항의 균형을 맞추기 위해 다이렉트 화면을 기반으로 다시 최적화되었습니다. 이로써 vivoX100s는 생체 역사상 가장 강력한 신호 수신 기능을 갖춘 휴대폰이 되었습니다. 새 휴대폰은 또한 안테나가 본체 주위에 분산된 독특한 360° 서라운드 디자인을 사용합니다. 이 디자인은 신호 강도를 향상시킬 뿐만 아니라 다양한 일상 자세를 최적화하여 부적절한 쥐기 방법으로 인해 발생하는 문제를 방지합니다.

Apple의 최신 iOS18, iPadOS18 및 macOS Sequoia 시스템 릴리스에는 사진 애플리케이션에 중요한 기능이 추가되었습니다. 이 기능은 사용자가 다양한 이유로 손실되거나 손상된 사진과 비디오를 쉽게 복구할 수 있도록 설계되었습니다. 새로운 기능에는 사진 앱의 도구 섹션에 '복구됨'이라는 앨범이 도입되었습니다. 이 앨범은 사용자가 기기에 사진 라이브러리에 포함되지 않은 사진이나 비디오를 가지고 있을 때 자동으로 나타납니다. "복구된" 앨범의 출현은 데이터베이스 손상으로 인해 손실된 사진과 비디오, 사진 라이브러리에 올바르게 저장되지 않은 카메라 응용 프로그램 또는 사진 라이브러리를 관리하는 타사 응용 프로그램에 대한 솔루션을 제공합니다. 사용자는 몇 가지 간단한 단계만 거치면 됩니다.

7월 29일 뉴스에 따르면 Honor X60i 휴대폰은 오늘부터 1,399위안부터 공식 판매되고 있다. 디자인 측면에서 Honor X60i 휴대폰은 중앙에 구멍이 있고 4면 모두 경계가 거의 없는 매우 좁은 테두리가 있는 직선형 스크린 디자인을 채택하여 시야를 크게 넓혔습니다. Honor X60i 매개변수 디스플레이: 6.7인치 고화질 디스플레이 배터리: 5000mAh 대용량 배터리 프로세서: Dimensity 6080 프로세서(TSMC 6nm, 2x2.4G A76+6×2G A55) 시스템: MagicOS8.0 시스템 기타 기능: 5G 신호 향상 , 스마트 캡슐, 언더스크린 지문, 듀얼 마이크, 소음 감소, 지식 Q&A, 사진 촬영 기능: 후면 듀얼 카메라 시스템: 5천만 화소 메인 카메라, 200만 화소 보조 렌즈, 전면 셀카 렌즈: 800만 화소, 가격: 8GB

MySQLi를 사용하여 PHP에서 데이터베이스 연결을 설정하는 방법: MySQLi 확장 포함(require_once) 연결 함수 생성(functionconnect_to_db) 연결 함수 호출($conn=connect_to_db()) 쿼리 실행($result=$conn->query()) 닫기 연결( $conn->close())

7월 19일 뉴스에 따르면, 첫 번째 플래그십 폴더블 폴더블폰인 샤오미 MIX Fold 4가 오늘 공식 출시됐으며 최초로 '3차원 특수형 배터리'를 탑재했다. 보도에 따르면 샤오미 MIX Fold4는 배터리 기술에서 획기적인 발전을 이루었으며 접이식 스크린을 위해 특별히 혁신적인 '3차원 특수형 배터리'를 설계했습니다. 기존 병풍장치는 공간 활용 효율이 낮은 기존의 각형 전지를 주로 사용하고 있다. 이 문제를 해결하기 위해 샤오미는 일반적인 와인딩 배터리 셀을 사용하지 않고 새로운 적층 공정을 개발하여 새로운 형태의 배터리를 만들어 공간 활용도를 크게 향상시켰습니다. 배터리 기술 혁신 양극 시트와 음극 시트를 정확하게 교대로 쌓고 리튬 이온의 안전한 매립을 보장하기 위해 Xiaomi는 용접 및 절단 정확도를 향상시키는 새로운 초음파 용접기와 라미네이션 기계를 개발했습니다.

PHP에서 데이터베이스 연결 오류를 처리하려면 다음 단계를 사용할 수 있습니다. mysqli_connect_errno()를 사용하여 오류 코드를 얻습니다. 오류 메시지를 얻으려면 mysqli_connect_error()를 사용하십시오. 이러한 오류 메시지를 캡처하고 기록하면 데이터베이스 연결 문제를 쉽게 식별하고 해결할 수 있어 애플리케이션이 원활하게 실행될 수 있습니다.

Xiaomi의 Redmi 브랜드는 포트폴리오에 또 다른 저가형 전화기인 Redmi 14C를 추가할 준비를 하고 있습니다. 해당 기기는 8월 31일 베트남에서 출시되는 것으로 확인됐다. 그러나 출시를 앞두고 베트남 소매업체를 통해 휴대폰 사양이 공개됐다. Redmi14CR Redmi는 종종 새로운 시리즈에서 새로운 디자인을 선보이며 Redmi14C도 예외는 아닙니다. 전화기 뒷면에는 대형 원형 카메라 모듈이 있는데, 이는 이전 제품의 디자인과 완전히 다릅니다. 블루 컬러 버전은 그라데이션 디자인까지 적용해 더욱 고급스러워 보인다. 그러나 Redmi14C는 실제로 경제적인 휴대폰입니다. 카메라 모듈은 4개의 링으로 구성됩니다. 하나는 기본 50 메가픽셀 센서를 수용하고 다른 하나는 깊이 정보를 위한 카메라를 수용할 수 있습니다.
