序文
すべての良い習慣は富です。この記事はMySQLに基づいています。SQL後悔医学、SQLパフォーマンスの最適化、SQL標準エレガンスの3つの方向に分かれています。SQLを書くための21の良い習慣を共有してください。読んでいただきありがとうございます。さあ〜
パブリックアカウント:「カタツムリを拾う小さな男の子」
1. SQLを記述した後、最初に実行計画を表示するように説明します(SQLパフォーマンスの最適化)
日常的にSQLを開発および作成する場合は、次の良い習慣を身に付けてください。SQLを作成した後、explainを使用して分析し、インデックスを使用するかどうかに特に注意してください。
explain select * from user where userid =10086 or age =18;
2.削除または更新ステートメントを操作し、制限を追加します(SQL後悔薬)
deleteまたはupdateステートメントを実行するときは、可能な限り制限を追加するようにしてください。例として次のSQLを取り上げます。
delete from euser where age > 30 limit 200;
制限を追加する主な利点は次のとおりです。
- 「間違ったSQLを書くコストを削減する」。コマンドラインでこのSQLを実行するときに、制限を超えない場合、実行中に「偶発的なハンドシェイク」が発生し、すべてのデータが削除される可能性があります。「間違った削除」を行うとどうなりますか?制限200を追加すると、それは異なります。エラーの削除は200個のデータの損失のみであり、binlogログを介して迅速に回復できます。
- 「SQLの効率が高くなる可能性が高い」、SQL行に制限1を追加し、最初の行がターゲットリターンに達した場合、制限がない場合、スキャンテーブルは引き続き実行されます。
- 「長いトランザクションを避ける」では、削除を実行するときに、ageがインデックスを追加すると、MySQLは関連するすべての行に書き込みロックとギャップロックを追加し、実行に関連するすべての行をロックします。削除の数が多いと、関連するビジネスに直接影響します。利用不可。
- 「データ量が多いとCPUがいっぱいになりやすい。」大量のデータを削除する場合は、レコード数を制限しないでください。cpuがいっぱいになりやすく、削除が遅くなります。
3.テーブルを設計するときに、対応するコメントをすべてのテーブルとフィールドに追加します(SQL仕様は洗練されています)
この良い習慣を身に付ける必要があります。データベーステーブルを設計するときは、すべてのテーブルとフィールドに対応するコメントが追加されるため、後で保守しやすくなります。
「正例:」
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`name` varchar(255) DEFAULT NULL COMMENT '账户名',
`balance` int(11) DEFAULT NULL COMMENT '余额',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='账户表';
「反例:」
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
`create_time` datetime NOT NULL ,
`update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8;
4. SQL書き込み形式、キーワードサイズの一貫性を保ち、インデントを使用します。(SQL仕様はエレガントです)
「正例:」
SELECT stu.name, sum(stu.score)
FROM Student stu
WHERE stu.classNo = '1班'
GROUP BY stu.name
「反例:」
SELECT stu.name, sum(stu.score) from Student stu WHERE stu.classNo = '1班' group by stu.name.
明らかに、一貫した大文字でキーワードを統合し、インデントの配置を使用すると、SQLがよりエレガントに見えます〜
5. INSERTステートメントは、対応するフィールド名を示します(SQL仕様エレガント)
「反例:」
insert into Student values ('666','捡田螺的小男孩','100');
「正例:」
insert into Student(student_id,name,score) values ('666','捡田螺的小男孩','100');
6.変更されたSQL操作は、最初にテスト環境で実行され、詳細な操作手順とロールバックプランが作成され、本番前に確認されます。(SQL後悔医学)
- 変更されたSQL操作は、構文エラーを回避して本番環境に移行するために、最初にテスト環境でテストされます。
- Sql操作を変更するには、特に次のような依存関係がある場合に、詳細な操作手順を指定する必要があります。最初にテーブル構造を変更してから、対応するデータを追加します。
- SQL操作を変更するためのロールバック計画があり、本番前に、対応する変更SQLを確認します。
7.データベーステーブルを設計するときに、プライマリキー、create_time、update_timeの3つのフィールドを追加します。(SQL仕様はエレガントです)
「反例:」
CREATE TABLE `account` (
`name` varchar(255) DEFAULT NULL COMMENT '账户名',
`balance` int(11) DEFAULT NULL COMMENT '余额',
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='账户表';
「正例:」
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`name` varchar(255) DEFAULT NULL COMMENT '账户名',
`balance` int(11) DEFAULT NULL COMMENT '余额',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8 ROW_FORMAT=REDUNDANT COMMENT='账户表';
「理由:」
- 主キーを追加する必要があります。主キーのないテーブルには魂がありません
- 作成時間と更新時間を追加することをお勧めします。詳細な監査と追跡の記録はすべて役に立ちます。
図に示すように、Ali開発マニュアルにもこの点が記載されています。
8. SQLステートメントを記述した後、where、order by、group byの背後にある列、および複数のテーブルに関連付けられた列にインデックスが付けられているかどうかを確認します。結合されたインデックスが優先されます。(SQLパフォーマンスの最適化)
「反例:」
select * from user where address ='深圳' order by age ;
「正例:」
添加索引
alter table user add index idx_address_age (address,age)
9.重要なデータを変更または削除する前に、バックアップ、最初にバックアップ、最初にバックアップ(SQL後悔医学)
データを変更または削除する場合は、SQLを実行する前に、変更するデータをバックアップする必要があります。誤操作の場合でも、「後悔の薬」を噛むことができます〜
10. whereの背後にあるフィールドは、そのデータタイプの暗黙的な変換に注意を払います(SQLパフォーマンスの最適化)
「反例:」
//userid 是varchar字符串类型
select * from user where userid =123;
「正例:」
select * from user where userid ='123';
「理由:」
- 一重引用符が追加されていない場合、文字列と数値の比較であり、型が一致しないため、MySQLは暗黙的な型変換を行い、浮動小数点数に変換してから比較し、最終的にインデックスを失敗させます。
11.すべての列をNOTNULLとして定義してみてください(SQL仕様エレガント)
- 「NOTNULL列はより多くのスペースを節約します。」NULL列は、NULLかどうかを判断するためのフラグとして追加のバイトが必要です。
- 「NULL列はヌルポインタの問題に注意を払う必要があります」。NULL列を計算して比較するときは、ヌルポインタの問題に注意を払う必要があります。
12. SQLを変更または削除するには、最初にWHEREを記述して確認し、確認後に削除または更新を追加します(SQL後悔医学)
特に、生成されたデータを操作するときに、変更または削除されたSQLが発生した場合は、最初にwhereクエリを追加し、[OK]を確認してから、更新または削除操作を実行します。
13. select *の代わりにselect <specific field>を使用するなど、不要なフィールドリターンを減らします(SQLパフォーマンスの最適化)
「反例:」
select * from employee;
「正例:」
select id,name from employee;
理由:
- リソースを節約し、ネットワークのオーバーヘッドを削減します。
- カバーインデックスは、バックテーブルを減らし、クエリの効率を向上させるために使用できます。
14.すべてのテーブルでInnodbストレージエンジンを使用する必要があります(SQL仕様エレガント)
Innodbは「トランザクションをサポートし、行レベルのロックをサポートし、回復性を向上させ」、高い同時実行性の下でパフォーマンスが向上するため、特別な要件はありません(つまり、列ストレージ、ストレージスペースデータなど、Innodbが満たすことができない機能)。 、すべてのテーブルでInnodbストレージエンジンを使用する必要があります
15.データベースとテーブルの文字セットは統一的にUTF8を使用します(SQL標準はエレガントです)
UTF8エンコーディングを均一に使用する
- 文字化けの問題を回避できます
- 異なる文字セットの比較と変換によって引き起こされるインデックス無効化の問題を回避できます
16.charの代わりにvarcharを使用してみてください。(SQLパフォーマンスの最適化)
「反例:」
`deptName` char(100) DEFAULT NULL COMMENT '部门名称'
「正例:」
deptName` varchar(100) DEFAULT NULL COMMENT '部门名称'
理由:
- 可変長フィールドのストレージスペースが小さいため、ストレージスペースを節約できます。
- 第二に、クエリの場合、比較的小さなフィールドでの検索がより効率的です。
17.フィールドの意味を変更したり、フィールドのステータスに追加したりする場合は、フィールドのコメントを時間内に更新する必要があります。(SQL仕様はエレガントです)
この点は、Ali開発マニュアルのMysqlプロトコルです。フィールド、特に列挙ステータスを表す場合、意味が変更された場合、またはステータスが追加された場合は、後でメンテナンスしやすくするために、フィールドのコメントをすぐに更新する必要があります。
18. SQLはデータを変更し、トランザクションの開始とコミットの習慣を身に付けます(SQL後悔医学)
「正例:」
begin;
update account set balance =1000000
where name ='捡田螺的小男孩';
commit;
「反例:」
update account set balance =1000000
where name ='捡田螺的小男孩';
- インデックスの命名は標準化する必要があります。プライマリキーインデックスの名前はpk_フィールド名、一意のインデックスの名前はuk _フィールド名、通常のインデックス名はidxフィールド名です。(SQL仕様は洗練されています)
説明:pkはプライマリキー、ukは一意のキー、idxはインデックスの省略形です。
20. WHERE句は、列に対して関数変換と式計算を実行しません
loginTimeにインデックスが付けられていると仮定します
「反例:」
select userId,loginTime from loginuser where Date_ADD(loginTime,Interval 7 DAY) >=now();
「正例:」
explain select userId,loginTime from loginuser where loginTime >= Date_ADD(NOW(),INTERVAL - 7 DAY);
「理由:」
- インデックス列でmysql組み込み関数を使用します。インデックスが無効です。
21.変更/更新するデータが多すぎる場合は、バッチで行うことを検討してください。
反例:
delete from account limit 100000;
正例:
for each(200次)
{
delete from account limit 500;
}
理由:
- 大規模なバッチ操作では、マスタースレーブの遅延が発生します。
- 大規模な操作では、大規模なトランザクションとブロックが生成されます。
- 大規模な操作とデータが多すぎると、cpuがいっぱいになります。
参考と感謝
- [削除後に制限を追加するのは良い習慣ですか?](https://blog.csdn.net/qq_39390545/article/details/107519747)
- 「アリ開発マニュアル」
公共