Các tính năng ẩn của MySQL


101

Tôi đã làm việc với Microsoft SQL Server nhiều năm nay nhưng chỉ mới bắt đầu sử dụng MySQL với các ứng dụng web của mình gần đây và tôi rất khao khát kiến ​​thức.

Để tiếp tục với hàng dài câu hỏi về "tính năng ẩn" , tôi muốn biết bất kỳ tính năng ẩn hoặc tiện dụng nào của MySQL, hy vọng sẽ cải thiện kiến ​​thức của tôi về cơ sở dữ liệu mã nguồn mở này.

Câu trả lời:


161

Kể từ khi bạn đặt tiền thưởng, tôi sẽ chia sẻ những bí mật khó giành được của tôi ...

Nói chung, tất cả các SQL mà tôi đã điều chỉnh ngày hôm nay đều yêu cầu sử dụng truy vấn phụ. Đến từ thế giới cơ sở dữ liệu Oracle, những thứ tôi cho là đương nhiên không hoạt động giống với MySQL. Và bài đọc của tôi về điều chỉnh MySQL khiến tôi kết luận rằng MySQL đứng sau Oracle về việc tối ưu hóa các truy vấn.

Mặc dù các truy vấn đơn giản cần thiết cho hầu hết các ứng dụng B2C có thể hoạt động tốt cho MySQL, nhưng hầu hết các loại truy vấn tổng hợp cần thiết cho Báo cáo thông minh dường như yêu cầu một chút lập kế hoạch và tổ chức lại các truy vấn SQL để hướng dẫn MySQL thực thi chúng nhanh hơn.

Quản trị:

max_connectionslà số lượng kết nối đồng thời. Giá trị mặc định là 100 kết nối (151 kể từ 5.0) - rất nhỏ.

Ghi chú:

kết nối chiếm bộ nhớ và hệ điều hành của bạn có thể không xử lý được nhiều kết nối.

Các mã nhị phân MySQL cho Linux / x86 cho phép bạn có tới 4096 kết nối đồng thời, nhưng các mã nhị phân tự biên dịch thường có ít giới hạn hơn.

Đặt table_cache để khớp với số lượng bảng đang mở và các kết nối đồng thời của bạn. Xem giá trị open_tables và nếu nó đang tăng nhanh, bạn sẽ cần tăng kích thước của nó.

Ghi chú:

2 tham số trước đó có thể yêu cầu rất nhiều tệp đang mở. 20 + max_connections + table_cache * 2 là một ước tính tốt cho những gì bạn cần. MySQL trên Linux có tùy chọn open_file_limit, hãy đặt giới hạn này.

Nếu bạn có các truy vấn phức tạp thì sort_buffer_size và tmp_table_size có thể rất quan trọng. Giá trị sẽ phụ thuộc vào độ phức tạp của truy vấn và các tài nguyên có sẵn, nhưng 4Mb và 32Mb, tương ứng là điểm khởi đầu được khuyến nghị.

Lưu ý: Đây là các giá trị "mỗi kết nối", trong số read_buffer_size, read_rnd_buffer_size và một số giá trị khác, có nghĩa là giá trị này có thể cần thiết cho mỗi kết nối. Vì vậy, hãy xem xét tải của bạn và tài nguyên có sẵn khi thiết lập các thông số này. Ví dụ: sort_buffer_size chỉ được cấp phát nếu MySQL cần thực hiện sắp xếp. Lưu ý: cẩn thận để không bị hết bộ nhớ.

Nếu bạn đã thiết lập nhiều kết nối (tức là một trang web không có kết nối liên tục), bạn có thể cải thiện hiệu suất bằng cách đặt thread_cache_size thành giá trị khác 0. 16 là giá trị tốt để bắt đầu. Tăng giá trị cho đến khi chủ đề của bạn không phát triển nhanh chóng.

KHÓA CHÍNH:

Chỉ có thể có một cột AUTO_INCREMENT trên mỗi bảng, cột này phải được lập chỉ mục và không được có giá trị DEFAULT

KEY thường là một từ đồng nghĩa với INDEX. Thuộc tính khóa PRIMARY KEY cũng có thể được chỉ định chỉ là KEY khi được đưa ra trong định nghĩa cột. Điều này được thực hiện để tương thích với các hệ thống cơ sở dữ liệu khác.

KHÓA CHÍNH là một chỉ mục duy nhất trong đó tất cả các cột chính phải được xác định là KHÔNG ĐỦ

Nếu chỉ mục PRIMARY KEY hoặc UNIQUE chỉ bao gồm một cột có kiểu số nguyên, bạn cũng có thể tham chiếu đến cột là "_rowid" trong câu lệnh SELECT.

Trong MySQL, tên của một KHÓA CHÍNH là CHÍNH

Hiện tại, chỉ có bảng InnoDB (v5.1?) Hỗ trợ khóa ngoại.

Thông thường, bạn tạo tất cả các chỉ mục bạn cần khi tạo bảng. Bất kỳ cột nào được khai báo là CHÍNH, KEY, UNIQUE hoặc INDEX sẽ được lập chỉ mục.

NULL có nghĩa là "không có giá trị". Để kiểm tra NULL, bạn không thể sử dụng các toán tử so sánh số học như =, <hoặc <>. Thay vào đó, hãy sử dụng toán tử IS NULL và IS NOT NULL:

NO_AUTO_VALUE_ON_ZERO ngăn tự động tăng số 0 để chỉ NULL tạo ra số thứ tự tiếp theo. Chế độ này có thể hữu ích nếu 0 đã được lưu trữ trong cột AUTO_INCREMENT của bảng. (Nhân tiện, lưu trữ 0 không phải là một phương pháp được khuyến khích.)

Để thay đổi giá trị của bộ đếm AUTO_INCREMENT được sử dụng cho các hàng mới:

ALTER TABLE mytable AUTO_INCREMENT = value; 

hoặc SET INSERT_ID = giá trị;

Trừ khi được chỉ định khác, giá trị sẽ bắt đầu bằng: 1000000 hoặc chỉ định nó như vậy:

...) ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 1

DẤU THỜI GIAN:

Giá trị cho các cột TIMESTAMP được chuyển đổi từ múi giờ hiện tại sang UTC để lưu trữ và từ UTC sang múi giờ hiện tại để truy xuất.

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html Đối với một cột TIMESTAMP trong bảng, bạn có thể chỉ định dấu thời gian hiện tại làm giá trị mặc định và giá trị tự động cập nhật.

một điều cần chú ý khi sử dụng một trong các loại này trong mệnh đề WHERE, tốt nhất là thực hiện WHERE datecolumn = FROM_UNIXTIME (1057941242) chứ không phải WHERE UNIX_TIMESTAMP (datecolumn) = 1057941242. làm như sau sẽ không tận dụng được chỉ mục trên cột đó.

http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

 UNIX_TIMESTAMP() 
 FROM_UNIXTIME() 
 UTC_DATE()
 UTC_TIME()
 UTC_TIMESTAMP()

nếu bạn chuyển đổi datetime sang unix timestamp trong MySQL:
Và sau đó thêm 24 giờ vào nó:
Và sau đó chuyển đổi nó trở lại datetime thì kỳ diệu sẽ mất một giờ!

Đây là những gì đang xảy ra. Khi chuyển đổi dấu thời gian unix trở lại ngày giờ, múi giờ được xem xét và điều đó xảy ra là từ ngày 28 đến ngày 29 tháng 10 năm 2006, chúng tôi đã tắt thời gian tiết kiệm ánh sáng ban ngày và mất một giờ.

Bắt đầu với MySQL 4.1.3, các hàm CURRENT_TIMESTAMP (), CURRENT_TIME (), CURRENT_DATE () và FROM_UNIXTIME () trả về các giá trị trong múi giờ hiện tại của kết nối , sẵn có dưới dạng giá trị của biến hệ thống múi giờ. Ngoài ra, UNIX_TIMESTAMP () giả định rằng đối số của nó là một giá trị datetime trong múi giờ hiện tại.

Cài đặt múi giờ hiện tại không ảnh hưởng đến các giá trị được hiển thị bởi các hàm như UTC_TIMESTAMP () hoặc các giá trị trong cột DATE, TIME hoặc DATETIME.

LƯU Ý: CHỈ CẬP NHẬT chỉ cập nhật DateTime nếu một trường bị thay đổi Nếu một CẬP NHẬT dẫn đến không có trường nào được thay đổi thì DateTime KHÔNG được cập nhật!

Ngoài ra, TIMESTAMP đầu tiên luôn được AUTOUPDATE theo mặc định ngay cả khi không được chỉ định

Khi làm việc với Dates, tôi hầu như luôn chuyển tải đến Julian Date becuase Toán dữ liệu sau đó là một vấn đề đơn giản về cộng hoặc trừ các số nguyên và Giây kể từ Nửa đêm vì lý do tương tự. Hiếm khi tôi cần thời gian thay đổi độ chi tiết nhỏ hơn vài giây.

Cả hai đều có thể được lưu trữ dưới dạng số nguyên 4 byte và nếu không gian thực sự chật hẹp, có thể được kết hợp thành thời gian UNIX (giây kể từ kỷ nguyên 1/1/1970) dưới dạng số nguyên không dấu sẽ tốt cho đến khoảng năm 2106 như sau:

'giây trong 24Hrs = 86400

'Giá trị tối đa của Số nguyên đã ký = 2.147.483.647 - có thể giữ 68 năm Giây

'Giá trị tối đa của số nguyên chưa ký = 4,294,967,295 - có thể giữ 136 năm Giây

Giao thức nhị phân:

MySQL 4.1 đã giới thiệu một giao thức nhị phân cho phép các giá trị dữ liệu không phải chuỗi được gửi và trả lại ở định dạng gốc mà không cần chuyển đổi sang và từ định dạng chuỗi. (Rất hữu ích)

Ngoài ra, mysql_real_query () nhanh hơn mysql_query () vì nó không gọi hàm strlen () để hoạt động trên chuỗi câu lệnh.

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html Giao thức nhị phân hỗ trợ các câu lệnh được chuẩn bị từ phía máy chủ và cho phép truyền các giá trị dữ liệu ở định dạng gốc. Giao thức nhị phân đã trải qua khá nhiều sửa đổi trong các bản phát hành trước đó của MySQL 4.1.

Bạn có thể sử dụng macro IS_NUM () để kiểm tra xem trường có kiểu số hay không. Chuyển giá trị kiểu cho IS_NUM () và nó đánh giá là TRUE nếu trường là số:

Một điều cần lưu ý là dữ liệu nhị phân CÓ THỂ được gửi bên trong một truy vấn thông thường nếu bạn thoát khỏi nó và hãy nhớ MySQL chỉ yêu cầu dấu gạch chéo ngược đó và ký tự trích dẫn được thoát. Vì vậy, đó là một cách thực sự dễ dàng để CHÈN các chuỗi nhị phân ngắn hơn như mật khẩu được mã hóa / muối chẳng hạn.

Máy chủ chính:

http://www.experts-exchange.com/Database/MySQL/Q_22967482.html

http://www.databasejournal.com/features/mysql/article.php/10897_3355201_2

CẤP PHÉP THAY THẾ CHẬM . thành slave_user IDENTIFIED BY 'slave_password'

#Master Binary Logging Config  STATEMENT causes replication 
              to be statement-based -  default

log-bin=Mike
binlog-format=STATEMENT
server-id=1            
max_binlog_size = 10M
expire_logs_days = 120    


#Slave Config
master-host=master-hostname
master-user=slave-user
master-password=slave-password
server-id=2

Tệp nhật ký nhị phân phải đọc:

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://www.mydigitallife.info/2007/10/06/how-to-read-mysql-binary-log-files-binlog-with-mysqlbinlog/

http://dev.mysql.com/doc/refman/5.1/en/mysqlbinlog.html

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://dev.mysql.com/doc/refman/5.1/en/binary-log-setting.html

Bạn có thể xóa tất cả các tệp nhật ký nhị phân bằng câu lệnh RESET MASTER hoặc một tập hợp con của chúng bằng PURGE MASTER

--result-file = binlog.txt TrustedFriend-bin.000030

Chuẩn hóa:

http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html

Các chức năng UDF

http://www.koders.com/cpp/fid10666379322B54AD41AEB0E4100D87C8CDDF1D8C.aspx

http://souptonuts.sourceforge.net/readme_mysql.htm

Loại dữ liệu:

http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

http://www.informit.com/articles/article.aspx?p=1238838&seqNum=2

http://bitfilm.net/2008/03/24/saving-bytes-enough-data-storage-mysql-part-1/

Một điều cần lưu ý là trên một bảng hỗn hợp có cả CHAR và VARCHAR, mySQL sẽ thay đổi CHAR thành VARCHAR

RecNum integer_type UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (RecNum)

MySQL luôn thể hiện các ngày bằng năm đầu tiên, phù hợp với các thông số kỹ thuật tiêu chuẩn của SQL và ISO 8601

Khác:

Việc loại bỏ một số chức năng MySQl sẽ dẫn đến các tệp dữ liệu nhỏ hơn và truy cập nhanh hơn. Ví dụ:

--datadir sẽ chỉ định thư mục dữ liệu và

--skip-innodb sẽ tắt tùy chọn đổi mới và giúp bạn tiết kiệm 10-20 triệu

Thêm tại đây http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

Tải xuống Chương 7 - Miễn phí

InnoDB là giao dịch nhưng có một chi phí hiệu suất đi kèm với nó. Tôi nhận thấy các bảng MyISAM là đủ cho 90% các dự án của tôi. Các bảng không an toàn cho giao dịch (MyISAM) có một số ưu điểm riêng của chúng, tất cả đều xảy ra vì:

không có chi phí giao dịch:

Nhanh hơn nhiều

Yêu cầu dung lượng đĩa thấp hơn

Cần ít bộ nhớ hơn để thực hiện cập nhật

Mỗi bảng MyISAM được lưu trữ trên đĩa trong ba tệp. Các tệp có tên bắt đầu bằng tên bảng và có phần mở rộng để chỉ ra loại tệp. Tệp .frm lưu trữ định dạng bảng. Tệp dữ liệu có phần mở rộng .MYD (MYData). Tệp chỉ mục có phần mở rộng .MYI (MYIndex).

Các tệp này có thể được sao chép nguyên vẹn vào vị trí lưu trữ mà không cần sử dụng tính năng Sao lưu quản trị viên MySQL, việc này tốn thời gian (Khôi phục cũng vậy)

Bí quyết là tạo một bản sao của các tệp này sau đó XÓA bảng. Khi bạn đặt các tập tin trở lại MySQl sẽ nhận ra chúng và cập nhật theo dõi bảng.

Nếu bạn phải Sao lưu / Khôi phục,

Việc khôi phục bản sao lưu hoặc nhập từ tệp kết xuất hiện có có thể mất nhiều thời gian tùy thuộc vào số lượng chỉ mục và khóa chính bạn có trên mỗi bảng. Bạn có thể tăng tốc quá trình này lên đáng kể bằng cách sửa đổi tệp kết xuất ban đầu của mình bằng cách bao quanh nó bằng những thứ sau:

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;

Để tăng đáng kể tốc độ tải lại, hãy thêm lệnh SQL SET AUTOCOMMIT = 0; ở đầu tệp kết xuất và thêm COMMIT; lệnh đến cùng.

Theo mặc định, autocommit được bật, có nghĩa là mỗi lệnh chèn trong tệp kết xuất sẽ được coi là một giao dịch riêng biệt và được ghi vào đĩa trước khi lệnh tiếp theo được bắt đầu. Nếu bạn không thêm các lệnh này, việc tải lại cơ sở dữ liệu lớn vào InnoDB có thể mất nhiều giờ ...

Kích thước tối đa của một hàng trong bảng MySQL là 65,535 byte

Độ dài tối đa hiệu dụng của một VARCHAR trong MySQL 5.0.3 và on = kích thước hàng tối đa (65,535 byte)

Giá trị VARCHAR không được đệm khi chúng được lưu trữ. Khoảng trắng cuối được giữ lại khi các giá trị được lưu trữ và truy xuất, tuân theo SQL tiêu chuẩn.

Giá trị CHAR và VARCHAR trong MySQL được so sánh mà không liên quan đến dấu cách ở cuối.

Sử dụng CHAR sẽ chỉ tăng tốc độ truy cập của bạn nếu toàn bộ bản ghi có kích thước cố định. Có nghĩa là, nếu bạn sử dụng bất kỳ đối tượng có kích thước thay đổi nào, bạn cũng có thể làm cho tất cả chúng có kích thước thay đổi. Bạn không tăng tốc độ bằng cách sử dụng một CHAR trong bảng cũng chứa một VARCHAR.

Giới hạn VARCHAR 255 ký tự đã được nâng lên 65535 ký tự kể từ MySQL 5.0.3

Tìm kiếm toàn văn bản chỉ được hỗ trợ cho các bảng MyISAM.

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

Cột BLOB không có bộ ký tự và việc sắp xếp và so sánh dựa trên giá trị số của các byte trong giá trị cột

Nếu chế độ SQL nghiêm ngặt không được bật và bạn chỉ định giá trị cho cột BLOB hoặc TEXT vượt quá độ dài tối đa của cột, giá trị sẽ bị cắt bớt cho vừa và cảnh báo sẽ được tạo.

Lệnh hữu ích:

kiểm tra chế độ nghiêm ngặt: SELECT @@ global.sql_mode;

tắt chế độ nghiêm ngặt:

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

hoặc xóa: sql-mode = "STRICT_TRANS_TABLES, ...

HIỂN THỊ CÁC CỘT TỪ mytable

CHỌN tối đa (số lượng tên) NHƯ virtualcolumnTỪ LỆNH trong bảng của tôi THEO cột ảo

http://dev.mysql.com/doc/refman/5.0/en/group-by-hiised-fields.html

http://dev.mysql.com/doc/refman/5.1/en/information-functions.html# Chức năng_last-insert-id last_insert_id ()

giúp bạn có PK của hàng cuối cùng được chèn vào tối đa luồng hiện tại (pkcolname) giúp bạn có PK cuối cùng về tổng thể.

Lưu ý: nếu bảng trống, max (pkcolname) trả về 1 mysql_insert_id () chuyển đổi kiểu trả về của hàm MySQL C API gốc mysql_insert_id () thành kiểu long (có tên int trong PHP).

Nếu cột AUTO_INCREMENT của bạn có loại cột là BIGINT, giá trị được trả về bởi mysql_insert_id () sẽ không chính xác. Thay vào đó, hãy sử dụng hàm MySQL SQL nội bộ LAST_INSERT_ID () trong một truy vấn SQL.

http://dev.mysql.com/doc/refman/5.0/en/information-functions.html# Chức năng_last-insert-id

Chỉ cần lưu ý rằng khi bạn đang cố gắng chèn dữ liệu vào bảng và bạn gặp lỗi:

Unknown column the first bit of data what you want to put into the table in field list

sử dụng một cái gì đó như

INSERT INTO table (this, that) VALUES ($this, $that)

đó là bởi vì bạn không có bất kỳ dấu nháy đơn nào xung quanh các giá trị mà bạn đang cố gắn vào bảng. Vì vậy, bạn nên thay đổi mã của mình thành:

INSERT INTO table (this, that) VALUES ('$this', '$that') 

nhắc nhở rằng `` được sử dụng để xác định các trường, cơ sở dữ liệu hoặc bảng MySQL, không phải giá trị;)

Mất kết nối với máy chủ trong khi truy vấn:

http://dev.mysql.com/doc/refman/5.1/en/gone-away.html

http://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html

http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html

http://dev.mysql.com/doc/refman/5.1/en/show-variables.html

http://dev.mysql.com/doc/refman/5.1/en/option-files.html

http://dev.mysql.com/doc/refman/5.1/en/error-log.html

Truy vấn điều chỉnh

http://www.artfulsoftware.com/infotree/queries.php?&bw=1313

Chà, thế là đủ để kiếm được tiền thưởng mà tôi nghĩ ... Thành quả của nhiều giờ và nhiều dự án với cơ sở dữ liệu miễn phí tuyệt vời . Tôi phát triển các máy chủ dữ liệu ứng dụng trên nền tảng windows chủ yếu bằng MySQL. Vấn đề tồi tệ nhất mà tôi phải giải quyết là

Cơn ác mộng cơ sở dữ liệu kế thừa MySQL cuối cùng

Điều này đòi hỏi một loạt các ứng dụng để xử lý các bảng thành một thứ gì đó hữu ích bằng cách sử dụng nhiều thủ thuật được đề cập ở đây.

Nếu bạn thấy điều này hữu ích một cách đáng kinh ngạc, hãy bày tỏ sự cảm ơn của bạn bằng cách bỏ phiếu cho nó.

Ngoài ra, hãy xem các bài báo và sách trắng khác của tôi tại: www.coastrd.com


22

Một trong những tính năng không quá ẩn của MySQL là nó không thực sự giỏi là SQL phù hợp, tốt, không lỗi thực sự, nhưng, nhiều gotchas ... :-)


Thông báo cho người khác biết rằng danh sách này rất có giá trị khi chuyển từ MSSQL sang MySQL. Cheers Mat.
GateKiller

Nhiều người trong số đó là từ các phiên bản MySQL trước đó.
jmucchiello

đối với một, tôi không nghĩ rằng sẽ có thể đặt giá trị NULL vào trường dấu thời gian.
mat

3
MySQL không đặc biệt tệ hơn trong việc tuân thủ SQL so với nhiều cơ sở dữ liệu khác; Miễn là bạn gắn bó với một tập hợp con SQL lành mạnh, bạn thường có thể tránh được các lỗi mắc phải - ví dụ như có thể nói nhiều hơn. Chuỗi rỗng NULL khét tiếng của Oracle.
bobince

1
Bạn có thể vô hiệu hóa một số gotchasSET SESSION sql_mode='ANSI';
Kornel

21

Một lệnh để tìm ra những bảng nào hiện có trong bộ nhớ cache:

mysql> SHOW open TABLES FROM test;
+----------+-------+--------+-------------+
| DATABASE | TABLE | In_use | Name_locked |
+----------+-------+--------+-------------+
| test     | a     |      3 |           0 |
+----------+-------+--------+-------------+
1 row IN SET (0.00 sec)

(Từ blog hiệu suất MySQL )


15

Lệnh để tìm ra ai đang làm gì:

mysql> show processlist;
show processlist;
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
| Id | User        | Host            | db   | Command | Time | State                            | Info             |
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
|  1 | root        | localhost:32893 | NULL | Sleep   |    0 |                                  | NULL             |
|  5 | system user |                 | NULL | Connect |   98 | Waiting for master to send event | NULL             |
|  6 | system user |                 | NULL | Connect | 5018 | Reading event from the relay log | NULL             |
+-----+------+-----------+---------+---------+-------+-------+------------------+
3 rows in set (0.00 sec) 

Và bạn có thể kết thúc một quá trình với:

mysql>kill 5 

5
cũng hiển thị DANH SÁCH QUY TRÌNH ĐẦY ĐỦ nếu bạn không muốn các truy vấn bị cắt bớt.
Greg

11

Tôi đặc biệt thích sự hỗ trợ tích hợp của MySQL cho inet_ntoa()inet_aton(). Nó làm cho việc xử lý địa chỉ IP trong bảng trở nên rất đơn giản (ít nhất là miễn là chúng chỉ là địa chỉ IPv4!)


2
PostgreSQL có một loại inet rất đẹp, xử lý ipv4 và ipv6 rất tốt :-)
mat

Tôi cũng đã từng thích chúng, nhưng không cần phải sử dụng chúng thì thậm chí còn tốt hơn. +1 cho Postgres.
Kornel

11

Tôi thích on duplicate key(nâng cấp AKA, hợp nhất) cho tất cả các loại bộ đếm được tạo một cách lười biếng:

insert into occurances(word,count) values('foo',1),('bar',1) 
  on duplicate key cnt=cnt+1

Bạn có thể chèn nhiều hàng trong một truy vấn và ngay lập tức xử lý chỉ mục trùng lặp cho mỗi hàng.


10

Một lần nữa - không thực sự ẩn các tính năng, nhưng thực sự tiện dụng:

Đặc tính

Dễ dàng lấy DDL:

SHOW CREATE TABLE CountryLanguage

đầu ra:

CountryLanguage | CREATE TABLE countrylanguage (
  CountryCode char(3) NOT NULL DEFAULT '',
  Language char(30) NOT NULL DEFAULT '',
  IsOfficial enum('T','F') NOT NULL DEFAULT 'F',
  Percentage float(4,1) NOT NULL DEFAULT '0.0',
  PRIMARY KEY (CountryCode,Language)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Tính năng: Hàm tổng hợp GROUP_CONCAT () Tạo một chuỗi liên kết các đối số của nó trên mỗi chi tiết và tổng hợp bằng cách nối các đối số trên mỗi nhóm.

Ví dụ 1: đơn giản

SELECT   CountryCode
,        GROUP_CONCAT(Language) AS List
FROM     CountryLanguage
GROUP BY CountryCode             

Đầu ra:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | Dutch,English,Papiamento,Spanish   |
. ...         . ...                                .
| ZWE         | English,Ndebele,Nyanja,Shona       |
+-------------+------------------------------------+

Ví dụ 2: nhiều đối số

SELECT   CountryCode
,        GROUP_CONCAT(
             Language
,            IF(IsOfficial='T', ' (Official)', '')
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

Đầu ra:

+-------------+---------------------------------------------+
| CountryCode | List                                        |
+-------------+---------------------------------------------+
| ABW         | Dutch (Official),English,Papiamento,Spanish |
. ...         . ...                                         .
| ZWE         | English (Official),Ndebele,Nyanja,Shona     |
+-------------+---------------------------------------------+

Ví dụ 3: Sử dụng dấu phân tách tùy chỉnh

SELECT   CountryCode
,        GROUP_CONCAT(Language SEPARATOR ' and ') AS List
FROM     CountryLanguage
GROUP BY CountryCode

Đầu ra:

+-------------+----------------------------------------------+
| CountryCode | List                                         |
+-------------+----------------------------------------------+
| ABW         | Dutch and English and Papiamento and Spanish |
. ...         . ...                                          .
| ZWE         | English and Ndebele and Nyanja and Shona     |
+-------------+----------------------------------------------+

Ví dụ 4: Kiểm soát thứ tự của các phần tử danh sách

SELECT   CountryCode
,        GROUP_CONCAT(
         Language
         ORDER BY CASE IsOfficial WHEN 'T' THEN 1 ELSE 2 END DESC
         ,        Language
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

Đầu ra:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | English,Papiamento,Spanish,Dutch,  |
. ...         . ...                                .
| ZWE         | Ndebele,Nyanja,Shona,English       |
+-------------+------------------------------------+

Tính năng: COUNT (DISTINCT) với nhiều biểu thức

Bạn có thể sử dụng nhiều biểu thức trong một biểu thức COUNT (DISTINCT ...) để đếm số lượng kết hợp.

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

Tính năng / Gotcha: Không cần bao gồm các biểu thức không tổng hợp trong danh sách GROUP BY

Hầu hết các RDBMS thực thi một GROUP BY tuân thủ SQL92 yêu cầu tất cả các biểu thức không tổng hợp trong danh sách CHỌN phải xuất hiện trong GROUP BY. Trong các RDBMS này, câu lệnh này:

SELECT     Country.Code, Country.Continent, COUNT(CountryLanguage.Language)
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

không hợp lệ vì danh sách CHỌN chứa cột Country.Continent không được tổng hợp không xuất hiện trong danh sách GROUP BY. Trong các RDBMS này, bạn phải sửa đổi danh sách GROUP BY để đọc

GROUP BY   Country.Code, Country.Continent

hoặc bạn phải thêm một số tổng hợp vô nghĩa vào Country.Continent, chẳng hạn

SELECT     Country.Code, MAX(Country.Continent), COUNT(CountryLanguage.Language)

Bây giờ, vấn đề là, về mặt logic, không có gì yêu cầu Country.Continent phải được kết hợp. Xem, Mã quốc gia là khóa chính của bảng Quốc gia. Country.Continent cũng là một cột từ bảng Country và do đó theo định nghĩa phụ thuộc về mặt chức năng vào Country.Code khóa chính. Vì vậy, phải tồn tại chính xác một giá trị trong Country.Continent cho mỗi Country.Code riêng biệt. Nếu bạn nhận ra điều đó, bạn nhận ra rằng không có ý nghĩa gì khi tổng hợp nó (chỉ có một giá trị, phải không) cũng như nhóm theo nó (vì nó sẽ không làm cho kết quả độc đáo hơn vì bạn đã nhóm theo pk)

Dù sao - MySQL cho phép bạn bao gồm các cột không tổng hợp trong danh sách CHỌN mà không yêu cầu bạn cũng phải thêm chúng vào mệnh đề GROUP BY.

Điểm mấu chốt ở đây là MySQL không bảo vệ bạn trong trường hợp bạn tình cờ sử dụng một cột không được tổng hợp. Vì vậy, một truy vấn như thế này:

SELECT     Country.Code, COUNT(CountryLanguage.Language), CountryLanguage.Percentage
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

Sẽ được thực thi mà không có khiếu nại, nhưng cột CountryLanguage.P phần trăm sẽ chứa phần trăm không có nghĩa (có nghĩa là, trong tất cả các ngôn ngữ phần trăm, một trong các giá trị có sẵn cho phần trăm sẽ được chọn ngẫu nhiên hoặc ít nhất là ngoài tầm kiểm soát của bạn.

Xem: Nhóm gỡ rối theo huyền thoại


Việc cho phép các cột không được khai báo theo nhóm là một trong những tính năng tôi thích nhất đến từ Oracle. Đó là một lỗi lớn nếu bạn đã quen với Oracle - nó chỉ cho phép bạn chạy truy vấn, kết quả trông đúng, nhưng sau đó bạn nhận ra rằng nó không làm như bạn nghĩ.
mbafford

7

Lệnh "pager" trong máy khách

Giả sử bạn có 10.000 hàng trong kết quả của mình và muốn xem chúng (Điều này giả sử các lệnh "less" và "tee" có sẵn, điều này thường xảy ra trong Linux; trong Windows YMMV.)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

Và bạn sẽ nhận được chúng trong trình xem tệp "ít hơn" để bạn có thể lướt qua chúng một cách độc đáo, tìm kiếm, v.v.

Cũng thế

pager tee myfile.txt
select a_few_things FROM tbl WHERE i_want_to_save_output_to_a_file;

Sẽ thuận tiện ghi vào một tập tin.


không may là dưới cửa sổ, ngay cả khi tồn tại "less" và "tee", bản thân tùy chọn máy nhắn tin không được hỗ trợ. không dễ dàng nào
Berry Tsakala

6

Một số điều bạn có thể thấy thú vị:

<query>\G -- \G in the CLI instead of the ; will show one column per row
explain <query>; -- this will show the execution plan for the query


3

Đây là một số mẹo của tôi - Tôi đã viết blog về chúng trong blog của mình ( Liên kết )

  1. Bạn không cần sử dụng dấu '@' khi khai báo biến.
  2. Bạn phải sử dụng dấu phân cách (mặc định là ';') để phân ranh giới phần cuối của một câu lệnh - Liên kết
  3. Nếu bạn đang cố gắng di chuyển dữ liệu giữa MS-SQL 2005 và mySQL, có một số vòng lặp để chuyển qua - Liên kết
  4. Thực hiện đối sánh phân biệt chữ hoa chữ thường trong mySQL - liên kết

3

Nếu bạn đang làm việc với các cơ sở dữ liệu InnoDb lớn và / hoặc giao dịch cao, hãy tìm hiểu và hiểu về Blog Hiệu suất Mysql "HIỂN THỊ TRẠNG THÁI" , nó sẽ trở thành bạn của bạn.


3

Nếu sử dụng cmdline Mysq, bạn có thể tương tác với dòng lệnh (trên máy Linux - không chắc có hiệu ứng tương đương trên Windows hay không) bằng cách sử dụng dấu thét / dấu chấm than. Ví dụ:

\! cat file1.sql

sẽ hiển thị mã cho file1.sql. Để lưu câu lệnh và truy vấn của bạn vào một tệp, hãy sử dụng cơ sở tee

\T filename

để tắt quyền sử dụng này \ t

Cuối cùng để chạy một tập lệnh bạn đã lưu, hãy sử dụng "tên tệp nguồn". Tất nhiên, giải pháp thay thế thông thường là nhập trực tiếp vào tên tập lệnh khi bắt đầu mysql từ dòng lệnh:

    mysql -u root -p < case1.sql

Hy vọng điều đó có ích cho ai đó!

Chỉnh sửa: Chỉ cần nhớ một cái khác - khi gọi mysql từ dòng lệnh, bạn có thể sử dụng chuyển đổi -t để đầu ra ở định dạng bảng - một lợi ích thực sự với một số truy vấn (mặc dù tất nhiên việc kết thúc truy vấn bằng \ G như đã đề cập ở nơi khác ở đây cũng là hữu ích về mặt này). Nhiều hơn nữa trên các công tắc khác nhau Công cụ dòng lệnh

Chỉ cần tìm ra một cách đơn giản để thay đổi thứ tự của một loại (thường sử dụng Case ...) Nếu bạn muốn thay đổi thứ tự của một loại (có thể sắp xếp theo 1, 4, 3, 2 thay vì 1, 2, 3, 4) bạn có thể sử dụng hàm trường trong mệnh đề Order by. Ví dụ

Đặt hàng theo trường (trường_sắp_xếp, 1,4,3,2)


3

Tôi không nghĩ đây là MySQL cụ thể, nhưng thật kỳ diệu cho tôi:

Thay vì viết

WHERE (x.id > y.id) OR (x.id = y.id AND x.f2 > y.f2) 

Bạn chỉ có thể viết

WHERE (x.id, x.f2) > (y.id, y.f2)

Điều đó thực sự tuyệt vời nhưng một số trường hợp sử dụng sẽ như thế nào?
xoàiDrunk

Nó có thể hữu ích để tìm tất cả các bản ghi lớn hơn một bản ghi nhất định.
Fantius

2

mysqlsla - Một trong những công cụ phân tích nhật ký truy vấn chậm được sử dụng rất phổ biến. Bạn có thể thấy 10 truy vấn tồi tệ nhất kể từ lần cuối bạn triển khai nhật ký truy vấn chậm. Nó cũng có thể cho bạn biết số lần truy vấn BAD đã được kích hoạt và tổng thời gian nó mất trên máy chủ.


2

Trên thực tế đã được ghi lại , nhưng rất khó chịu: chuyển đổi tự động cho ngày không chính xác và đầu vào không chính xác khác.

Trước MySQL 5.0.2, MySQL đã tha thứ cho các giá trị dữ liệu bất hợp pháp hoặc không phù hợp và ép buộc chúng về các giá trị pháp lý để nhập dữ liệu. Trong MySQL 5.0.2 trở lên, đó vẫn là hành vi mặc định, nhưng bạn có thể thay đổi chế độ SQL của máy chủ để chọn cách xử lý truyền thống hơn đối với các giá trị xấu để máy chủ từ chối chúng và hủy bỏ câu lệnh mà chúng xuất hiện.

Đối với ngày tháng: đôi khi bạn sẽ "may mắn" khi MySQL không điều chỉnh đầu vào thành các ngày hợp lệ gần đó, mà thay vào đó lưu trữ nó 0000-00-00theo định nghĩa là không hợp lệ. Tuy nhiên, ngay cả khi đó bạn có thể muốn MySQL không thành công hơn là âm thầm lưu trữ giá trị này cho bạn.



1

Theo mặc định, InnoDB lưu trữ tất cả các bảng trong một không gian bảng toàn cầu sẽ không bao giờ thu nhỏ .

Bạn có thể sử dụng cách innodb_file_per_tablenày sẽ đặt mỗi bảng trong một vùng bảng riêng biệt sẽ bị xóa khi bạn thả bảng hoặc cơ sở dữ liệu.

Lập kế hoạch trước cho việc này vì bạn phải kết xuất và khôi phục cơ sở dữ liệu để lấy lại dung lượng.

Sử dụng không gian bảng trên mỗi bảng


1

Nếu bạn chèn vào cột datetime giá trị chuỗi trống "", MySQL sẽ giữ nguyên giá trị là 00/00/0000 00:00:00. Không giống như Oracle, sẽ lưu giá trị null.


1

Trong các điểm chuẩn của tôi với các tập dữ liệu lớn và các trường DATETIME, việc thực hiện truy vấn này luôn chậm hơn:

SELECT * FROM mytable
WHERE date(date_colum) BETWEEN '2011-01-01' AND ''2011-03-03';

Hơn cách tiếp cận này:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.