2008-09-14 75 views
28

我有一張網址表,我不想要任何重複的網址。如何使用PHP/MySQL檢查一個給定的URL是否已經在表中?如何檢查一個值是否已經存在以避免重複?

+2

很多答案都建議在'url'列中添加`UNIQUE`約束。有一件事要記住,MySQL限制了密鑰的大小。根據您在URL中允許的最大字節數,這可能是個問題。 [5.6參考手冊陳述](http://dev.mysql.com/doc/refman/5.6/en/create-index.html):「對於MyISAM表,」[A]前綴長度最長可達1000字節,並且InnoDB表的767字節「。 – 2011-08-21 18:51:21

回答

39

如果你不希望有重複你可以做以下操作:

如果多個用戶可以將數據插入數據庫,@Jeremy Ruten建議的方法,可以導致錯誤:執行檢查後,某人可以向表中插入類似的數據。

+0

如果你插入了一個副本,那麼`INSERT IGNORE`應該比`REPLACE`更快。作爲額外的好處,你可以知道它是否是新的,因爲MySQL返回受影響的行數(使用`ROW_COUNT()`或API)。它也適用於多行插入。 – 2011-08-20 02:08:31

-1

你能做到這一點查詢:

SELECT url FROM urls WHERE url = 'http://asdf.com' LIMIT 1 

然後檢查mysql_num_rows() == 1,看它是否存在。

+0

當您插入時檢查時,如何防止另一個連接輸入具有該值的行? – 2008-09-14 01:17:47

+1

將其包裝到TRANSACTION中 – 2008-09-14 01:18:49

2

我不知道MySQL的語法,但所有你需要做的就是用IF語句包裝你的INSERT語句,它將查詢表並查看給定的URL EXISTS是否存在 - 不插入一個新的紀錄。

如果MSSQL你可以這樣做:

IF NOT EXISTS (SELECT 1 FROM YOURTABLE WHERE URL = 'URL') 
INSERT INTO YOURTABLE (...) VALUES (...) 
+1

可能不總是在並行環境中工作。 – 2011-08-18 16:48:23

0

如果你只是想要一個是或否的答案,這個語法應該給你最好的性能。

select if(exists (select url from urls where url = 'http://asdf.com'), 1, 0) from dual
0

如果你只是想確保有沒有重複,然後添加一個唯一索引URL字段,這樣就沒有必要明確檢查URL存在,只需要插入正常,如果已經存在,那麼插入將失敗並出現重複鍵錯誤。

13

爲了保證唯一性,您需要添加一個唯一的約束。假設你的表的名稱是「網址」和列名是「URL」,你可以用這個alter table命令添加唯一約束:

alter table urls add constraint unique_url unique (url); 

的ALTER TABLE可能會失敗,如果(誰真正與MySQL知道)您的表格中已經有了重複的網址。

14

你是否只關心完全相同的字符串的網址..如果有的話,其他答案中有很多好的建議。還是你也不得不擔心封聖?

例如:http://google.comhttp://go%4fgle.com是完全相同的URL,但可以通過任何僅限數據庫的技術進行復制。如果這是一個問題,您應該預處理URL以解析和字符轉義序列。

根據URL來自哪裏,您也必須擔心參數以及它們在您的應用程序中是否顯着。

1

如果你想在表中插入urls,但只有那些不存在的,你可以在列上添加一個UNIQUE約束,並在你的INSERT查詢中添加IGNORE,這樣你就不會收到錯誤。

例子:INSERT INTO忽略SET urls URL =「網址到插入」

0

的答案取決於你是否想知道什麼時候進行的嘗試輸入一個記錄,一個重複字段。如果你不在乎,那麼使用「INSERT ... ON DUPLICATE KEY」語法,因爲這將使你的嘗試悄然成功,而不會產生重複。

另一方面,如果您想知道何時發生此類事件並防止它發生,那麼您應該使用唯一的鍵約束,這將導致試圖插入/更新失敗,並顯示有意義的錯誤。

0
$url = "http://www.scroogle.com"; 

$query = "SELECT `id` FROM `urls` WHERE `url` = '$url' "; 
$resultdb = mysql_query($query) or die(mysql_error()); 
list($idtemp) = mysql_fetch_array($resultdb) ; 

if(empty($idtemp)) // if $idtemp is empty the url doesn't exist and we go ahead and insert it into the db. 
{ 
    mysql_query("INSERT INTO urls (`url`) VALUES('$url') ") or die (mysql_error()); 
}else{ 
    //do something else if the url already exists in the DB 
} 
6

簡單的SQL解決方案需要一個唯一的字段;邏輯解決方案沒有。

你應該規範你的網站,以確保沒有重複。在PHP中的函數如strtolower()urldecode()rawurldecode()

假設:您的表名是'網站',您的網址的列名是'網址',並且與該網址相關聯的任意數據位於'data'列中。

邏輯解決方案

SELECT COUNT(*) AS UrlResults FROM websites WHERE url='http://www.domain.com' 

測試之前的查詢與如果SQL或PHP語句,以確保它是0,你繼續使用INSERT語句之前。

簡單的SQL語句

方案1:你的數據庫是先到先得的表,你有沒有希望在未來重複的條目。

ALTER TABLE websites ADD UNIQUE (url) 

這將防止任何條目能夠被輸入到數據庫,如果URL值已經存在於該列中。

場景2:您希望獲得每個網址的最新信息並且不希望重複內容。這種情況有兩種解決方案。 (這些解決方案還需要「網址」是唯一的,這樣在方案解決方案1 ​​也需要進行。)

REPLACE INTO websites (url, data) VALUES ('http://www.domain.com', 'random data') 

這將觸發一個DELETE操作,如果行存在,隨後在INSERT所有的情況下,所以要小心ON DELETE聲明。

INSERT INTO websites (url, data) VALUES ('http://www.domain.com', 'random data') 
ON DUPLICATE KEY UPDATE data='random data' 

如果行存在,將觸發UPDATE操作,如果不存在則觸發INSERT。

14

首先,準備數據庫

  • 域名不區分大小寫,但您必須假定URL的其餘部分是。 (並不是所有的網絡服務器都會尊重URL中的大小寫,但大多數都會這樣做,而且您無法通過查看來輕鬆分辨。)
  • 假設您需要存儲多個域名,請使用區分大小寫的排序規則。
  • 如果您決定將URL存儲在兩列中(一個用於域名,另一個用於資源定位器),請考慮對域名使用不區分大小寫的排序規則以及資源定位符的區分大小寫排序規則。如果我是你,我會測試兩種方式(一列中的URL與兩列中的URL)。
  • 在URL列上放置一個UNIQUE約束。或者在一對列上,如果將域名和資源定位器存儲在單獨的列中,則爲UNIQUE (url, resource_locator)
  • 使用CHECK()約束將編碼的URL保留在數據庫之外。此CHECK()約束對於防止不良數據通過大容量副本或SQL外殼進入不可或缺。

其次,準備URL

,如果你只插入的URL,沒有測試它的存在首先。相反,如果值已經存在,請嘗試插入並捕獲將得到的錯誤。測試和插入爲每個新URL都點擊數據庫兩次。插入和陷阱只需要訪問一次數據庫。請注意,插入和陷阱與insert-and-ignore-errors不同。只有一個特定的錯誤意味着你違反了獨特的約束;其他錯誤意味着還有其他問題。

在另一方面,如果你有在同一行中其他一些數據一起插入URL,你需要決定的時候,你是否會通過

更換無需陷阱重複鍵錯誤,但它可能有不幸的副作用,如果有外鍵引用。

+1

如何在URL中添加urldecode()以解決Rob Walker在答案中提出的問題?或者至少在其域名部分 – Mike 2011-08-18 15:24:38

+1

PHP在dbms之外,這意味着每個其他可能插入URL的應用程序都必須記住要麼通過PHP應用程序,要麼開發具有相同行爲的代碼。但是,在db外使用urldecode(),在db內部使用CHECK()約束是一種可靠的,依賴於應用程序的方法。 – 2011-08-18 16:47:54

+1

OP確實說過PHP/MySQL,但是,這也可以使用存儲過程完成(例如http://snippets.dzone.com/posts/show/7746) – Mike 2011-08-18 17:13:16

0

使列的primary key

23

要回答你最初的問題,檢查是否有重複的最簡單的方法是運行鍼對你想添加什麼樣的SQL查詢!

。例如,如果你想在表links來檢查網址http://www.example.com/,然後將查詢將看起來像

SELECT * FROM links WHERE url = 'http://www.example.com/'; 

你的PHP代碼會看起來像

$conn = mysql_connect('localhost', 'username', 'password'); 
if (!$conn) 
{ 
    die('Could not connect to database'); 
} 
if(!mysql_select_db('mydb', $conn)) 
{ 
    die('Could not select database mydb'); 
} 

$result = mysql_query("SELECT * FROM links WHERE url = 'http://www.example.com/'", $conn); 

if (!$result) 
{ 
    die('There was a problem executing the query'); 
} 

$number_of_rows = mysql_num_rows($result); 

if ($number_of_rows > 0) 
{ 
    die('This URL already exists in the database'); 
} 

我已經寫了這一點手寫在這裏,所有的連接到數據庫,等等。這可能是因爲你已經有一個數據庫的連接,所以你應該使用,而不是開始一個新的連接(更換$connmysql_query命令,並把該東東刪除做mysql_connectmysql_select_db

當然,也有連接到數據庫,像PDO,或使用ORM或類似的其他方式,所以如果你已經使用這些,這個答案可能不相關(而且它可能有點超出範圍,在這裏給出與此相關的解答!)

然而,MySQL提供了許多方法來防止這種在第一時間發生的事情。

首先,你可以標記一個字段作爲「唯一」。

可以說我有一個表,我想只是存儲鏈接到從我的站點中的所有網址,以及他們最後一次進行了走訪。

我的定義可能是這個樣子: -

CREATE TABLE links 
(
    url VARCHAR(255) NOT NULL, 
    last_visited TIMESTAMP 
) 

這將讓我一遍又一遍地添加相同的URL,除非我寫類似於上面的一些PHP代碼來阻止這種情況發生。

但是,是我的定義更改爲

CREATE TABLE links 
(
    url VARCHAR(255) NOT NULL, 
    last_visited TIMESTAMP, 
    PRIMARY KEY (url) 
) 

那麼這將使MySQL拋出一個錯誤,當我試圖插入相同值的兩倍。

在PHP的一個例子是

$result = mysql_query("INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()", $conn); 

if (!$result) 
{ 
    die('Could not Insert Row 1'); 
} 

$result2 = mysql_query("INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()", $conn); 

if (!$result2) 
{ 
    die('Could not Insert Row 2'); 
} 

如果你跑了這一點,你會發現,在第一次嘗試,該腳本將與評論Could not Insert Row 2死亡。然而,在隨後的運行中,它會死於Could not Insert Row 1

這是因爲MySQL知道url是主要的表的關鍵。主鍵是該行的唯一標識符。大多數情況下,將行的唯一標識符設置爲數字很有用。這是因爲MySQL查找數字比查找文本更快。在MySQL中,鍵(特別是主鍵)用於定義兩個表之間的關係。舉例來說,如果我們得到廣大用戶的表,我們可以把它定義爲

CREATE TABLE users (
    username VARCHAR(255) NOT NULL, 
    password VARCHAR(40) NOT NULL, 
    PRIMARY KEY (username) 
) 

然而,當我們想存儲有關用戶已經發了一個帖子的信息,我們就必須將用戶名存儲與該職位以確定該帖子屬於該用戶。

我已經提到MySQL查找數字比字符串更快,所以這意味着當我們不需要時,我們會花時間查找字符串。

爲了解決這個問題,我們可以添加一個額外的列,USER_ID,使主鍵(因此要查找基於對某個帖子的用戶記錄時,我們可以發現它更快)

CREATE TABLE users (
    user_id INT(10) NOT NULL AUTO_INCREMENT, 
    username VARCHAR(255) NOT NULL, 
    password VARCHAR(40) NOT NULL, 
    PRIMARY KEY (`user_id`) 
) 

你會注意到我還在這裏添加了新的東西 - AUTO_INCREMENT。這基本上允許我們讓這個領域照顧自己。每插入一個新行,它都會將前一個數字加1,並存儲該數字,所以我們不必擔心編號問題,並且可以讓它自行完成此操作。

因此,與上表中,我們可以這樣做

INSERT INTO users (username, password) VALUES('Mez', 'd3571ce95af4dc281f142add33384abc5e574671'); 

然後

INSERT INTO users (username, password) VALUES('User', '988881adc9fc3655077dc2d4d757d480b5ea0e11'); 

的東西。當我們從數據庫中選擇記錄,我們得到如下: -

mysql> SELECT * FROM users; 
+---------+----------+------------------------------------------+ 
| user_id | username | password         | 
+---------+----------+------------------------------------------+ 
|  1 | Mez  | d3571ce95af4dc281f142add33384abc5e574671 | 
|  2 | User  | 988881adc9fc3655077dc2d4d757d480b5ea0e11 | 
+---------+----------+------------------------------------------+ 
2 rows in set (0.00 sec) 

但是,在這裏 - 我們遇到了問題 - 我們仍然可以使用相同的用戶名添加其他用戶!顯然,這是我們不想做的事情!

mysql> SELECT * FROM users; 
+---------+----------+------------------------------------------+ 
| user_id | username | password         | 
+---------+----------+------------------------------------------+ 
|  1 | Mez  | d3571ce95af4dc281f142add33384abc5e574671 | 
|  2 | User  | 988881adc9fc3655077dc2d4d757d480b5ea0e11 | 
|  3 | Mez  | d3571ce95af4dc281f142add33384abc5e574671 | 
+---------+----------+------------------------------------------+ 
3 rows in set (0.00 sec) 

讓我們改變我們的表格定義!

CREATE TABLE users (
    user_id INT(10) NOT NULL AUTO_INCREMENT, 
    username VARCHAR(255) NOT NULL, 
    password VARCHAR(40) NOT NULL, 
    PRIMARY KEY (user_id), 
    UNIQUE KEY (username) 
) 

讓我們看看當我們現在嘗試插入同一個用戶兩次會發生什麼。

mysql> INSERT INTO users (username, password) VALUES('Mez', 'd3571ce95af4dc281f142add33384abc5e574671'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO users (username, password) VALUES('Mez', 'd3571ce95af4dc281f142add33384abc5e574671'); 
ERROR 1062 (23000): Duplicate entry 'Mez' for key 'username' 

Huzzah !!我們現在嘗試第二次插入用戶名時會出現錯誤。使用類似上面的內容,我們可以在PHP中檢測到這一點。

現在,讓我們回到我們的鏈接表,但有一個新的定義。

CREATE TABLE links 
(
    link_id INT(10) NOT NULL AUTO_INCREMENT, 
    url VARCHAR(255) NOT NULL, 
    last_visited TIMESTAMP, 
    PRIMARY KEY (link_id), 
    UNIQUE KEY (url) 
) 

讓我們在數據庫中插入「http://www.example.com」。

INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()); 

如果我們嘗試並重新插入....

ERROR 1062 (23000): Duplicate entry 'http://www.example.com/' for key 'url' 

但是,如果我們要更新上次訪問的時間會發生什麼?

好了,我們可以做一些複雜的,使用PHP,像這樣: -

$result = mysql_query("SELECT * FROM links WHERE url = 'http://www.example.com/'", $conn); 

if (!$result) 
{ 
    die('There was a problem executing the query'); 
} 

$number_of_rows = mysql_num_rows($result); 

if ($number_of_rows > 0) 
{ 
    $result = mysql_query("UPDATE links SET last_visited = NOW() WHERE url = 'http://www.example.com/'", $conn); 

    if (!$result) 
    { 
     die('There was a problem updating the links table'); 
    } 
} 

或者,甚至搶在數據庫中的行的id,並用它來更新它。

$ result = mysql_query(「SELECT * FROM links WHERE url ='http://www.example.com/'」,$ conn);

if (!$result) 
{ 
    die('There was a problem executing the query'); 
} 

$number_of_rows = mysql_num_rows($result); 

if ($number_of_rows > 0) 
{ 
    $row = mysql_fetch_assoc($result); 

    $result = mysql_query('UPDATE links SET last_visited = NOW() WHERE link_id = ' . intval($row['link_id'], $conn); 

    if (!$result) 
    { 
     die('There was a problem updating the links table'); 
    } 
} 

但是,MySQL有內置的功能,一個漂亮的叫REPLACE INTO

讓我們來看看它是如何工作的。

mysql> SELECT * FROM links; 
+---------+-------------------------+---------------------+ 
| link_id | url      | last_visited  | 
+---------+-------------------------+---------------------+ 
|  1 | http://www.example.com/ | 2011-08-19 23:48:03 | 
+---------+-------------------------+---------------------+ 
1 row in set (0.00 sec) 

mysql> INSERT INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()); 
ERROR 1062 (23000): Duplicate entry 'http://www.example.com/' for key 'url' 
mysql> REPLACE INTO links (url, last_visited) VALUES ('http://www.example.com/', NOW()); 
Query OK, 2 rows affected (0.00 sec) 

mysql> SELECT * FROM links; 
+---------+-------------------------+---------------------+ 
| link_id | url      | last_visited  | 
+---------+-------------------------+---------------------+ 
|  2 | http://www.example.com/ | 2011-08-19 23:55:55 | 
+---------+-------------------------+---------------------+ 
1 row in set (0.00 sec) 

注意使用REPLACE INTO時,它的更新的last_visited時間,而不是拋出一個錯誤!

這是因爲MySQL檢測到您正試圖替換一行。它知道你想要的行,因爲你已經將url設置爲唯一的。 MySQL通過使用傳入的位應該是唯一的(在本例中爲url)並更新該行的其他值來計算要替換的行。它也更新了link_id - 這有點意外! (事實上​​,我沒有意識到這會發生,直到我看到它發生!)

但是,如果你想添加一個新的URL?那麼,REPLACE INTO會很高興地插入一個新的行,如果它找不到匹配的唯一行!

mysql> REPLACE INTO links (url, last_visited) VALUES ('http://www.stackoverflow.com/', NOW()); 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT * FROM links; 
+---------+-------------------------------+---------------------+ 
| link_id | url       | last_visited  | 
+---------+-------------------------------+---------------------+ 
|  2 | http://www.example.com/  | 2011-08-20 00:00:07 | 
|  3 | http://www.stackoverflow.com/ | 2011-08-20 00:01:22 | 
+---------+-------------------------------+---------------------+ 
2 rows in set (0.00 sec) 

我希望這會回答你的問題,並且給你更多關於MySQL如何工作的信息!

0

您可以使用自聯接來定位(和刪除)。表中有一些網址,也有一些PK(我們知道,PK 不是的URL,否則你將不會被允許有重複)

SELECT 
    * 
FROM 
    yourTable a 
JOIN 
    yourTable b -- Join the same table 
     ON b.[URL] = a.[URL] -- where the URL's match 
     AND b.[PK] <> b.[PK] -- but the PK's are different 

這將返回已複製的URL所有行。

說,但是,你想只選擇重複並排除原來的....好吧,你需要決定什麼構成原件。對於這個答案的目的,讓我們假設最低的PK是「原始」

所有你需要做的是以下條款添加到上面的查詢:

WHERE 
    a.[PK] NOT IN (
     SELECT 
      TOP 1 c.[PK] -- Only grabbing the original! 
     FROM 
      yourTable c 
     WHERE 
      c.[URL] = a.[URL] -- has the same URL 
     ORDER BY 
      c.[PK] ASC) -- sort it by whatever your criterion is for "original" 

現在你有一個集中所有的非原始重複行。你可以很容易地執行一個DELETE或任何你喜歡從這個結果集。

請注意,這種方法可能效率不高,部分原因是mySQL並不總是處理IN,但我從OP瞭解到,這在桌面上是「清理」的,而不總是檢查。

如果您要檢查在INSERT時間的值是否已經存在,如果你得到一個結果,那麼你可以得出結論的價值已經在您的數據庫至少存在,你可以運行像這樣

SELECT 
    1 
WHERE 
    EXISTS (SELECT * FROM yourTable WHERE [URL] = 'testValue') 

一旦。

1

第一件事是第一件事。如果你還沒有創建表,或者你創建了一個表,但是沒有數據,那麼你需要添加一個唯一的constriant或唯一的索引。有關在索引或約束之間進行選擇的更多信息,請參見文章末尾。但他們都完成同樣的事情,強制該列只包含唯一值。

要在此列上創建具有唯一索引的表,您可以使用。

CREATE TABLE MyURLTable(
ID INTEGER NOT NULL AUTO_INCREMENT 
,URL VARCHAR(512) 
,PRIMARY KEY(ID) 
,UNIQUE INDEX IDX_URL(URL) 
); 

如果你只是想要一個獨特的約束,並在該表沒有索引,則可以使用

CREATE TABLE MyURLTable(
ID INTEGER NOT NULL AUTO_INCREMENT 
,URL VARCHAR(512) 
,PRIMARY KEY(ID) 
,CONSTRAINT UNIQUE UNIQUE_URL(URL) 
); 

現在,如果你已經有一個表,並且在它沒有數據,然後您可以使用以下某個代碼將索引或約束添加到表中。現在

ALTER TABLE MyURLTable 
ADD UNIQUE INDEX IDX_URL(URL); 

ALTER TABLE MyURLTable 
ADD CONSTRAINT UNIQUE UNIQUE_URL(URL); 

,你可能已經在它的一些數據的表格。在這種情況下,你可能已經有一些重複的數據。你可以嘗試創建上面顯示的constriant或index,如果你已經有重複的數據,它會失敗。如果你沒有重複的數據,那麼很好,如果你這樣做,你必須刪除重複的數據。使用以下查詢,您可以看到一串重複的網址。

SELECT URL,COUNT(*),MIN(ID) 
FROM MyURLTable 
GROUP BY URL 
HAVING COUNT(*) > 1; 

以刪除重複行,並保留一個,請執行以下操作:

DELETE RemoveRecords 
FROM MyURLTable As RemoveRecords 
LEFT JOIN 
(
SELECT MIN(ID) AS ID 
FROM MyURLTable 
GROUP BY URL 
HAVING COUNT(*) > 1 
UNION 
SELECT ID 
FROM MyURLTable 
GROUP BY URL 
HAVING COUNT(*) = 1 
) AS KeepRecords 
ON RemoveRecords.ID = KeepRecords.ID 
WHERE KeepRecords.ID IS NULL; 

現在你已經刪除了所有的記錄,你可以繼續創建您的索引或約束。現在,如果你想在你的數據庫中插入一個值,你應該使用類似的東西。

INSERT IGNORE INTO MyURLTable(URL) 
VALUES('http://www.example.com'); 

這將試圖做插入,如果它發現重複,什麼都不會發生。現在,讓我們說你有其他專欄,你可以做這樣的事情。

INSERT INTO MyURLTable(URL,Visits) 
VALUES('http://www.example.com',1) 
ON DUPLICATE KEY UPDATE Visits=Visits+1; 

這看起來會嘗試插入值,如果找到該URL,那麼它會通過遞增訪問計數器來更新記錄。當然,你總是可以做一個普通的舊插入,並處理你的PHP代碼中產生的錯誤。現在,至於你是否應該使用約束或索引,這取決於很多因素。索引可以加快查找速度,所以當表格變大時,性能會更好,但存儲索引會佔用額外的空間。索引通常也會使插入和更新花費更長的時間,因爲它必須更新索引。然而,由於必須以任何方式查看該值,爲了強制實現唯一性,在這種情況下,無論如何索引索引可能會更快。至於任何與性能相關的問題,答案都是嘗試兩種選擇並分析結果,以查看哪種方法最適合您的情況。

4

在考慮解決這個問題時,您需要首先定義「重複URL」對於您的項目意味着什麼。這將決定如何在將URL添加到數據庫之前canonicalize

至少有兩個定義:

  1. 兩個URL被視爲重複,如果它們表示相同的資源一無所知有關生成相應內容對應的網絡服務。一些考慮因素包括:
  2. 應用基本的URL規範化(例如小寫方案和域名,提供默認端口,通過參數名稱提供穩定的排序查詢參數,在HTTP和HTTPS的情況下移除哈希部分...) 考慮了Web服務的知識。也許你會認爲所有的Web服務都足夠聰明,可以對Unicode輸入進行規範化(例如維基百科),所以你可以應用Unicode Normalization Form Canonical Composition(NFC)。您可以從所有堆棧溢出URL中去除「www.」。您可以使用PostRank的postrank-uri代碼移植到PHP,以移除各種不必要的URL(例如&utm_source=...)。

定義1導致一個穩定的解決方案(即沒有進一步的規範化可以執行,並且URL的規範化不會改變)。定義2,我認爲是人們認爲URL規範化的定義,導致規範化例程,可以在不同的時刻產生不同的結果。

無論您選擇哪種定義,我建議您爲方案,登錄,主機,端口和路徑部分使用單獨的列。這將允許您智能地使用索引。方案和主機的列可以使用字符整理(所有字符整理在MySQL中都不區分大小寫),但登錄和路徑的列需要使用二進制,不區分大小寫的整理。另外,如果使用定義2,則需要保留原始方案,權限和路徑部分,因爲某些規範化規則可能會不時添加或刪除。

編輯:下面是示例表定義:

CREATE TABLE `urls1` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `scheme` VARCHAR(20) NOT NULL, 
    `canonical_login` VARCHAR(100) DEFAULT NULL COLLATE 'utf8mb4_bin', 
    `canonical_host` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_unicode_ci', /* the "ci" stands for case-insensitive. Also, we want 'utf8mb4_unicode_ci' 
rather than 'utf8mb4_general_ci' because 'utf8mb4_general_ci' treats accented characters as equivalent. */ 
    `port` INT UNSIGNED, 
    `canonical_path` VARCHAR(4096) NOT NULL COLLATE 'utf8mb4_bin', 

    PRIMARY KEY (`id`), 
    INDEX (`canonical_host`(10), `scheme`) 
) ENGINE = 'InnoDB'; 


CREATE TABLE `urls2` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 
    `canonical_scheme` VARCHAR(20) NOT NULL, 
    `canonical_login` VARCHAR(100) DEFAULT NULL COLLATE 'utf8mb4_bin', 
    `canonical_host` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_unicode_ci', 
    `port` INT UNSIGNED, 
    `canonical_path` VARCHAR(4096) NOT NULL COLLATE 'utf8mb4_bin', 

    `orig_scheme` VARCHAR(20) NOT NULL, 
    `orig_login` VARCHAR(100) DEFAULT NULL COLLATE 'utf8mb4_bin', 
    `orig_host` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_unicode_ci', 
    `orig_path` VARCHAR(4096) NOT NULL COLLATE 'utf8mb4_bin', 

    PRIMARY KEY (`id`), 
    INDEX (`canonical_host`(10), `canonical_scheme`), 
    INDEX (`orig_host`(10), `orig_scheme`) 
) ENGINE = 'InnoDB'; 

表`urls1`是用於根據定義1。表`urls2`是用於根據定義2.

存儲規範的URL存儲規範網址

不幸的是,由於MySQL限制了InnoDB密鑰的長度,所以你不能在元組('scheme` /`canonical_scheme`,`canonical_login`,`canonical_host`,`port`,`canonical_path`)上指定UNIQUE約束到767字節。

相關問題