DELETE và TRUNCATE

SQL Server cung cấp 2 phương pháp để xóa dữ liệu, DELETE và TRUNCATE. Cú pháp của hai lệnh này như sau:

DELETE

DELETE dbo.Tblxxx WHERE...

hoặc

DELETE a FROM dbo.Tblxxx a WHERE...

Khi cần xóa dữ liệu với điều kiện liên quan đến bảng khác:

DELETE a
FROM dbo.Tblxxx a
JOIN dbo.Tblyyy b ON a.Col1 = b.Col1

hoặc:

DELETE a
FROM dbo.Tblxxx a
WHERE EXISTS(SELECT 1 FROM dbo.Tblyyy b WHERE a.Col1 = b.Col1)

TRUNCATE không có tùy biến nào

TRUNCATE TABLE dbo.Tblxxx

 

Tuy cùng để xóa dữ liệu, nhưng hai lệnh này có những khác nhau cơ bản:

  • DELETE cung cấp các lựa chọn để xóa những dòng dữ liệu thỏa mãn các điều kiện nhất định, như WHERE hoặc JOIN với các bảng khác.
    TRUNCATE không có lựa chọn nào, mà luôn cắt bỏ toàn bộ dữ liệu của bảng. Nói cách khác, ta không thể TRUNCATE 1 nửa hay 1 phần của bảng.
  • DELETE hỗ trợ transaction. Khi lệnh DELETE nằm trong 1 transaction và trong một tình huống nào đó transaction được ROLLBACK thì các bản ghi bị xóa bởi lệnh DELETE sẽ trở lại bảng không có gì suy xuyển.
    TRUNCATE thì ngược lại, không hỗ trợ transaction. Một khi đã thực hiện thì không thể lấy lại dữ liệu được nữa.
  • DELETE khi thực hiện bao gồm quá trình tìm các bản ghi thỏa mãn điều kiện của câu lệnh, và xóa các bản ghi này. Việc tìm các bản ghi cần xóa được thực hiện giống hệt như một câu lệnh SELECT, cũng tối ưu hóa, lựa chọn giữa các phương án thực hiện khác nhau và chọn ra phương án tối ưu (dựa vào index, statistics…).
    TRUNCATE thì chỉ có một phương án thực hiện duy nhất, đó là cắt bỏ tất cả các dòng dữ liệu của bảng.
  • Với DELETE, các bản ghi bị xóa sẽ được kiểm tra xem có vi phạm ràng buộc FOREIGN KEY không. Ví dụ ta có hai bảng MAT_HANG và BAN_HANG là quan hệ 1-n thông qua MA_MH; nếu MA_MH=1 đã có giao dịch, nghĩa là bảng BAN_HANG đã có bản ghi với MA_MH=1, thì khi DELETE bản ghi với MA_MH=1 từ bảng MAT_HANG (bảng cha) SQL SERVER sẽ báo lỗi và không cho xóa.
    Nếu trước đó, khi ta định nghĩa ràng buộc FOREIGN KEY mà có lựa chọn CASCADE DELETE, thì thay vì báo lỗi SQL Server sẽ đồng thời xóa hết các bản ghi trong cả bảng BAN_HANG với MA_MH=1.
  • TRUNCATE thì không có những đoạn kiểm tra dài dòng như thế. Nếu bảng có ràng buộc FOREIGN KEY, SQL Server sẽ báo lỗi và không cho thực hiện (nhớ là lựa chọn CASCADE DELETE trong khai báo FOREIGN KEY chỉ ảnh hưởng đến lệnh DELETE chứ không tác dụng đối với TRUNCATE).
  • Vì DELETE hỗ trợ transaction và dùng transaction log, nó có thể dùng với bảng nằm trong một replication hoặc database có dùng log shipping.
    TRUNCATE thì vì không ghi gì vào transaction log nên khi gặp một trong các tình huống trên sẽ bị từ chối ngay.
  • Với DELETE, nếu bảng có index thì các index cũng sẽ được cập nhật để xóa đi các node tương ứng với các bản ghi bị xóa.
    TRUNCATE thì rất đơn giản, các index của bảng cũng bị cắt cụt theo.
  • DELETE không ảnh hưởng đến giá trị IDENTITY. Nếu bảng có 100 bản ghi và cột IDENTITY có giá trị từ 1-100; nay ta DELETE bản ghi có cột IDENTITY=100 rồi INSERT một bản ghi mới; bản ghi mới sẽ có cột IDENTITY=101.
    TRUNCATE luôn đặt lại IDENTITY trở về 1. Bản ghi đầu tiên được INSERT sau khi TRUNCATE sẽ có cột IDENTITY=1.
  • DELETE thực ra chỉ đánh dấu xóa các bản ghi chứ ngay sau đó dữ liệu của các bản ghi bị xóa vẫn nằm nguyên tại chỗ. Dần dần khi ta INSERT thêm dữ liệu vào bảng thì các bản ghi mới sẽ ghi đè lên các vùng lưu trữ đó. Ta có thể kiểm tra để thấy kích thước bảng không thay đổi ngay cả sau khi chạy DELETE FROM TblName (xóa hết các bản ghi).
    TRUNCATE thì xóa hết dữ liệu đồng thời giải phóng vùng lưu trữ giành cho bảng, trả lại cho SQL Server. Ta có thể so sánh DELETE như là xóa file, còn TRUNCATE thì như format lại ổ cứng.
  • DELETE cho phép áp dụng đối với bảng ở server khác được nối qua linked server.
    TRUNCATE không cho phép điều này, bạn chỉ có thể TRUNCATE bảng nằm trên cùng server.

Vì những lý do trên, DELETE luôn luôn chậm hơn TRUNCATE. Càng có nhiều bản ghi DELETE càng chậm, còn TRUNCATE thì không phụ thuộc vào lượng dữ liệu. DELETE có phạm vi ứng dụng rộng hơn; còn TRUNCATE chỉ dùng được mỗi một việc, nhưng nó lại làm rất nhanh. Vì vậy, hãy nhớ dùng TRUNCATE khi có thể được.

How To Fix Time Difference Between Ubuntu And Windows

Recently LinuxAndUbuntu reader raised an issue that he was having with his dual boot. When he restarts from Ubuntu to Windows, the time in Windows changes. Here is why it happens and how you can fix it easily from Ubuntu.

Why There Is Time Difference Between Ubuntu And Windows ?

The time in Windows changes due to the ways both systems differently stores the time in the hardware clock. Ubuntu stores the time in UTC while Windows in Local time  so when user restarts Windows any number of time, the time does not change but when the user restarts from Windows into Ubuntu and then restarts back into Windows, the hardware clock has stored the time in UTC and now Windows changes it into Local time which cause the issue.

Here Is How Time Difference Between Ubuntu And Windows Can Be Fixed

Time difference can easily be resolved by changing the time from UTC to Local in Ubuntu. To do this simply edit the “/etc/default/rcS” file and change “UTC=no” to “UTC=yes” (without quotes). Now Ubuntu will store time in hardware clock in Local time instead of UTC so there won’t be any conflictions between Ubuntu and Windows. To do this automatically, use the following command in terminal –

$ sudo sed -i ‘s/UTC=yes/UTC=no/’ /etc/default/rcS
Although setting up time in UTC is beneficial because you don’t need to change the hardware clock when moving between timezones.

Fixing Time Difference From Windows

The above was the solution to time difference from Ubuntu, now let’s see how to fix it from Windows –

First of all download the below registry file and double click it to install.

windowstimefixutc.reg

Download File


After extracting registry, run command prompt as an administrator and enter the following command –
sc config w32time start= disabled
You are done! Now reboot the system for changes to take effects.

Install Oracle Java 8 / 9 in Ubuntu 16.04, Linux Mint 18

Oracle Java JDK 9

Webupd8 Team is maintaining a PPA repository with installer scripts for the latest Java 8 and 9, that automatically downloads the Java archive from Oracle website and sets up everything for you.

1. Add the PPA.

Open terminal (Ctrl+Alt+T) and run the command:

sudo add-apt-repository ppa:webupd8team/java

Type in your password when it asks and hit Enter.

java-installer-ppa

2. Update and install the installer script:

Run commands to update system package index and install Java installer script:

sudo apt update; sudo apt install oracle-java8-installer

You may replace oracle-java8-installer with oracle-java9-installer to install Java 9.

While the install process, you have to accept Java license to continue downloading & installing Java binaries.

Oracle Java License

3. Check the Java version

To check the Java version after installing the package, run command:

javac -version

check out java version

4. Set Java environment variables

The PPA also contains a package to automatically set Java environment variables, just run command:

sudo apt install oracle-java8-set-default

For Java 9, install the package oracle-java9-set-default instead.

SQL: PostgreSQL trigger for deleting old records

System log files can be easily managed using logrotate to archive old entries, but when logging to a database table you will typically need to write your own script.

In the following example we’ve created a TRIGGER that is called automatically by PostgreSQL that has the effect of deleting ‘stale’ records.

The obvious advantage being that it’s always associated with the database and will be included in any backups. It also doesn’t require any CRON script.

1. The situation

In this simple example we’ve created a log of the ip address of visitors to a certain part of a website, and the timestamp of each visit:

CREATE TABLE limiter ( ip varchar NOT NULL, timestamp timestamp NOT NULL DEFAULT NOW() );

Data is added using a simple INSERT statement called from PHP:

This logs thousands of entries each day, but for our purposes the data only needs to be kept for up to 48 hours, so at regular intervals we call a DELETE function:

Simple enough, and it works, but lets see how we can better automate this using a trigger.

2. Creating the TRIGGER function

The following code creates a basic trigger that deletes old rows from the table as before:

CREATE FUNCTION delete_old_rows() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN DELETE FROM limiter WHERE timestamp < NOW() - INTERVAL '2 days'; RETURN NULL; END; $$;

We plan to call this using AFTER INSERT so the RETURN value is not used can can be ‘NULL’.

3. Calling the TRIGGER

Finally, we set the trigger to be called every time a new record is inserted into the table:

CREATE TRIGGER trigger_delete_old_rows AFTER INSERT ON limiter EXECUTE PROCEDURE delete_old_rows();

And we’re done. Every time a new row is inserted into this table, our trigger function is called and deletes any records older than 48 hours.

4. Adding DIAGNOSTICS

As a final step we’re going to modify the trigger so that it also reports the number of rows that have been deleted:

CREATE FUNCTION delete_old_rows() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE row_count int; BEGIN DELETE FROM limiter WHERE timestamp < NOW() - INTERVAL '2 days'; IF found THEN GET DIAGNOSTICS row_count = ROW_COUNT; RAISE NOTICE 'DELETEd % row(s) FROM limiter', row_count; END IF; RETURN NULL; END; $$;

Now when any rows are deleted a NOTICE is raised:

postgres=# INSERT INTO limiter VALUES ('1.2.3.4'); NOTICE: DELETEd 136 row(s) FROM limiter INSERT 0 1

For those paying attention, note that we’re not actually making use of the NOTICE text in our PHP code, but it could be logged for debugging purposes in the PostgreSQL log file.

5. VIEWing TRIGGER details

From the command-line interface you can view the TABLE details as follows:

# \d limiter Table "public.limiter" Column | Type | Modifiers -----------+-----------------------------+------------------------ ip | character varying | not null timestamp | timestamp without time zone | not null default now() Triggers: trigger_delete_old_rows AFTER INSERT ON limiter FOR EACH STATEMENT EXECUTE PROCEDURE delete_old_rows()

And to see the TRIGGER definition and code:

# \x Expanded display is on. # \df+ delete_old_rows List of functions -[ RECORD 1 ]-------+------------------------------------------------------------------- Schema | public Name | delete_old_rows Result data type | trigger Argument data types | Type | trigger Security | invoker Volatility | volatile Owner | postgres Language | plpgsql Source code | | DECLARE | row_count int; | BEGIN | DELETE FROM limiter WHERE timestamp < NOW() - INTERVAL '2 days'; | IF found THEN | GET DIAGNOSTICS row_count = ROW_COUNT; | RAISE NOTICE 'DELETEd % row(s) FROM limiter', row_count; | END IF; | RETURN NULL; | END;

Using just \df instead of \df+ you will only see the Scheme, Name, Result and Argument data types, and Type. Not particularly useful.