সমস্ত কলামগুলি আপডেট করার ওভারহেড কী, এমনকি যেগুলি পরিবর্তন হয়নি [বন্ধ]


17

যখন একটি সারি আপডেট করার কথা আসে, তখন অনেকগুলি ORM সরঞ্জাম একটি আপডেটের বিবৃতি দেয় যা সেই নির্দিষ্ট সত্তার সাথে সম্পর্কিত প্রতিটি কলাম সেট করে

সুবিধাটি হ'ল আপনি সহজেই আপডেট স্টেটমেন্টগুলিকে ব্যাচ করতে পারেন যেহেতু UPDATEআপনি যে সত্তার কোনও বৈশিষ্ট্যই বদলে ফেলুন স্টেটমেন্টটি একই। আরও, আপনি এমনকি সার্ভার-সাইড এবং ক্লায়েন্ট-সাইড স্টেটমেন্ট ক্যাশেও ব্যবহার করতে পারেন।

সুতরাং, যদি আমি কোনও সত্তা লোড করি এবং কেবলমাত্র একক সম্পত্তি সেট করি:

Post post = entityManager.find(Post.class, 1L);
post.setScore(12);

সমস্ত কলাম পরিবর্তন করা যাচ্ছে:

UPDATE post
SET    score = 12,
       title = 'High-Performance Java Persistence'
WHERE  id = 1

এখন, ধরে নিই যে আমাদের titleসম্পত্তিতেও একটি সূচক রয়েছে , ডিবি বুঝতে হবে না যে মানটি কোনওভাবেই পরিবর্তিত হয়নি?

ইন এই নিবন্ধটি , মার্কুস Winand বলেছেন:

সমস্ত কলামের আপডেট একই প্যাটার্নটি দেখায় যা আমরা ইতিমধ্যে পূর্ববর্তী বিভাগগুলিতে পর্যবেক্ষণ করেছি: প্রতিটি অতিরিক্ত সূচকের সাথে প্রতিক্রিয়া সময় বৃদ্ধি পায়।

আমি ভাবছি কেন এই ওভারহেড যেহেতু ডেটাবেসটি সম্পর্কিত ডেটা পৃষ্ঠাটিকে ডিস্ক থেকে মেমরিতে লোড করে এবং তাই এটি একটি কলাম মান পরিবর্তন করতে হবে কিনা তা নির্ধারণ করতে পারে।

এমনকি সূচকের ক্ষেত্রেও কোনও কিছুতে ভারসাম্য বজায় রাখার দরকার নেই যেহেতু পরিবর্তিত হয়নি এমন কলামগুলির জন্য সূচকগুলির মান পরিবর্তন হয় না, তবুও সেগুলি আপডেটের অন্তর্ভুক্ত ছিল।

এটি কি অপ্রয়োজনীয় কলামগুলির সাথে যুক্ত বি + ট্রি সূচকগুলিকেও নেভিগেট করা দরকার, কেবল ডাটাবেসেই বুঝতে পারে যে পাতার মান এখনও একইরকম?

অবশ্যই কিছু ওআরএম সরঞ্জাম আপনাকে কেবল পরিবর্তিত বৈশিষ্ট্যগুলি আপডেট করতে দেয়:

UPDATE post
SET    score = 12,
WHERE  id = 1

তবে বিভিন্ন ধরণের আলাদা আলাদা সারির জন্য পরিবর্তন করা হলে এই ধরণের আপডেটের ব্যাচ আপডেটগুলি বা স্টেটমেন্ট ক্যাশে থেকে সর্বদা উপকার পাবেন না।


1
ডাটাবেস যদি পোস্টগ্রিসএসকিউএল (বা কিছু অন্যান্য যা এমভিসিসি ব্যবহার করে ) হয়, তবে UPDATEএটি কার্যতঃ একটি DELETE+ এর সমতুল্য INSERT(কারণ আপনি প্রকৃতপক্ষে সারিটির একটি নতুন ভি ersion তৈরি করেন)। ওভারহেড উচ্চ, এবং সূচকের সংখ্যা সহ বৃদ্ধি পায় , বিশেষত যদি তাদের সমন্বিত অনেকগুলি কলামগুলি আসলে আপডেট হয় এবং সূচকে উপস্থাপন করতে ব্যবহৃত গাছ (বা যাই হোক না কেন) একটি উল্লেখযোগ্য পরিবর্তন প্রয়োজন। এটি প্রাসঙ্গিক কী তা আপডেট হওয়া কলামগুলির সংখ্যা নয় তবে আপনি কোনও সূচকের কলামের অংশ আপডেট করেন কিনা।
joanolo

@ জোয়ানোলো এমভিসিসির পোস্টগ্রিসের প্রয়োগের ক্ষেত্রে এটি কেবল সত্য হওয়া দরকার। মাইএসকিউএল, ওরাকল (এবং অন্যান্য) স্থানে একটি আপডেট করে এবং পরিবর্তিত কলামগুলি ইউএনডিও স্পেসে স্থানান্তরিত করে।
মরগান টকার

2
আমার উল্লেখ করা উচিত যে একটি ভাল ওআরএমের উচিত কোন কলামগুলিতে আপডেট হওয়া দরকার তা ট্র্যাক করা উচিত এবং ডাটাবেসে প্রেরিত বিবৃতিটি অনুকূলিত করা উচিত। এটি প্রাসঙ্গিক, কেবলমাত্র ডিবিতে সংক্রমণিত পরিমাণের জন্য, বিশেষত যদি কিছু কলাম দীর্ঘ পাঠ্য হয় সংক্রমণিত বা বিএলওবি হয়
joanolo

1
এসকিউএল সার্ভারের জন্য এটি নিয়ে আলোচনা করা প্রশ্ন dba.stackexchange.com/q/114360/3690
মার্টিন স্মিথ

2
আপনি কোন ডিবিএমএস ব্যবহার করছেন?
a_horse_with_no_name

উত্তর:


12

আমি জানি যে আপনি বেশিরভাগ ক্ষেত্রে UPDATEএবং প্রায়শই পারফরম্যান্স সম্পর্কে উদ্বিগ্ন , তবে সহযোগী "ওআরএম" রক্ষণকারী হিসাবে, আমাকে "পরিবর্তিত" , "নাল" এবং "ডিফল্ট" মানগুলির মধ্যে পার্থক্য করার সমস্যা সম্পর্কে আরও একটি দৃষ্টিভঙ্গি দেই এসকিউএলে তিনটি ভিন্ন জিনিস, তবে সম্ভবত জাভা এবং বেশিরভাগ ওআরএম-তে কেবল একটি জিনিস:

আপনার যুক্তি INSERTবিবৃতিতে অনুবাদ করা

ব্যাচ্যাবিলিটি এবং স্টেটমেন্ট ক্যাশেবিলিটির পক্ষে আপনার যুক্তিগুলি একইভাবে সত্য hold INSERT বিবৃতি হিসাবে তারা জন্য কি UPDATEবিবৃতি। তবে INSERTবিবৃতিগুলির ক্ষেত্রে, বিবৃতি থেকে একটি কলাম বাদ দেওয়া এর চেয়ে আলাদা শব্দার্থবিজ্ঞান রয়েছে UPDATE। এর অর্থ প্রয়োগ করা DEFAULT। নিম্নলিখিত দুটি শব্দার্থগতভাবে সমতুল্য:

INSERT INTO t (a, b)    VALUES (1, 2);
INSERT INTO t (a, b, c) VALUES (1, 2, DEFAULT);

এটি সত্য নয় UPDATEযেখানে প্রথম দুটি শব্দার্থগত সমতুল্য এবং তৃতীয়টির সম্পূর্ণ ভিন্ন অর্থ রয়েছে:

-- These are the same
UPDATE t SET a = 1, b = 2;
UPDATE t SET a = 1, b = 2, c = c;

-- This is different!
UPDATE t SET a = 1, b = 2, c = DEFAULT;

জেডিবিসি সহ বেশিরভাগ ডাটাবেস ক্লায়েন্টের এপিআই, এবং এর ফলস্বরূপ, জেপিএ একটি বাঁধাইয়ের অনুমতি দেয় না DEFAULT একটি বাইন্ড ভেরিয়েবলের সাথে এক্সপ্রেশনকে আবদ্ধ করার - বেশিরভাগ কারণ দেয় না। আপনি যদি পূর্বোক্ত ব্যাচিবিলিটি এবং স্টেটমেন্ট ক্যাশেযোগ্যতার কারণে একই এসকিউএল স্টেটমেন্টটি আবার ব্যবহার করতে চান তবে আপনি উভয় ক্ষেত্রে নিম্নলিখিত বিবৃতিটি ব্যবহার করবেন (ধরে নিবেন (a, b, c)যে সমস্ত কলাম এতে রয়েছে t):

INSERT INTO t (a, b, c) VALUES (?, ?, ?);

এবং যেহেতু cসেট করা নেই, আপনি সম্ভবত জাভাটিকেnull তৃতীয় বাইন্ড ভেরিয়েবলের সাথে বাঁধতে পারবেন, কারণ অনেকগুলি ওআরএম এছাড়াও NULLএবং DEFAULT( জোকিউকিউ , উদাহরণস্বরূপ এখানে ব্যতিক্রম হিসাবে) এর মধ্যে পার্থক্য করতে পারে না । তারা কেবল জাভা দেখেন nullএবং জানেন না যে এর অর্থ NULL(অজানা মান DEFAULTহিসাবে ) বা ( অজানা মান হিসাবে ) রয়েছে কিনা ।

অনেক ক্ষেত্রে, এই পার্থক্যটি কোনও বিষয় নয়, তবে আপনার কলাম সি সি নিম্নলিখিত বৈশিষ্ট্যগুলির কোনওটি ব্যবহার করছে যদি বিবৃতিটি কেবল ভুল হয় :

  • এটির একটি DEFAULTধারা রয়েছে
  • এটি একটি ট্রিগার দ্বারা উত্পাদিত হতে পারে

UPDATEবিবৃতি ফিরে

উপরের সমস্ত ডাটাবেসের ক্ষেত্রে সত্য হলেও, আমি আপনাকে নিশ্চিত করতে পারি যে ট্রিগার সমস্যাটি ওরাকল ডাটাবেসের ক্ষেত্রেও সত্য। নিম্নলিখিত এসকিউএল বিবেচনা করুন:

CREATE TABLE x (a INT PRIMARY KEY, b INT, c INT, d INT);

INSERT INTO x VALUES (1, 1, 1, 1);

CREATE OR REPLACE TRIGGER t
  BEFORE UPDATE OF c, d
  ON x
BEGIN
  IF updating('c') THEN
    dbms_output.put_line('Updating c');
  END IF;
  IF updating('d') THEN
    dbms_output.put_line('Updating d');
  END IF;
END;
/

SET SERVEROUTPUT ON
UPDATE x SET b = 1 WHERE a = 1;
UPDATE x SET c = 1 WHERE a = 1;
UPDATE x SET d = 1 WHERE a = 1;
UPDATE x SET b = 1, c = 1, d = 1 WHERE a = 1;

আপনি উপরের রান করার সময়, আপনি নিম্নলিখিত আউটপুট দেখতে পাবেন:

table X created.
1 rows inserted.
TRIGGER T compiled
1 rows updated.
1 rows updated.
Updating c

1 rows updated.
Updating d

1 rows updated.
Updating c
Updating d

যেমন আপনি দেখতে পাচ্ছেন, যে বিবৃতি সর্বদা সমস্ত কলামকে আপডেট করে তা সবসময় সমস্ত কলামের জন্য ট্রিগারকে আগুন ধরিয়ে দেবে, অন্যদিকে কেবল যে কলামগুলি পরিবর্তিত হয়েছে তা আপডেট করে এমন বিবৃতি কেবলমাত্র সেই ট্রিগারগুলিকেই আগুন ধরিয়ে দেবে যারা এই জাতীয় পরিবর্তনের জন্য শোনেন।

অন্য কথায়:

হাইবারনেটের বর্তমান আচরণ যা আপনি বর্ণনা করছেন তা অসম্পূর্ণ এবং এটি ট্রিগার (এবং সম্ভবত অন্যান্য সরঞ্জাম) এর উপস্থিতিতেও ভুল হিসাবে বিবেচিত হতে পারে।

আমি ব্যক্তিগতভাবে মনে করি যে আপনার ক্যোয়ারী ক্যাশে অপ্টিমাইজেশান যুক্তিটি গতিশীল এসকিউএল এর ক্ষেত্রে ওভাররেটেড হয়েছে। নিশ্চিত, যেমন একটি ক্যাশের মধ্যে আরো কয়েকটি প্রশ্নের হবে, এবং একটি বিট আরো পার্স কাজ সম্পন্ন করা হবে, কিন্তু এই সাধারণত গতিশীল জন্য একটা সমস্যা হয় না UPDATEবিবৃতির তুলনায় অনেক কম, SELECT

ব্যাচিং অবশ্যই একটি সমস্যা, তবে আমার মতে, সমস্ত কলামগুলিকে আপডেট করার জন্য একটি একক আপডেটকে স্বাভাবিক করা উচিত নয় কারণ এই বিবৃতিটি ব্যাচিয়াযোগ্য হওয়ার সামান্য সম্ভাবনা রয়েছে। সম্ভাবনাগুলি হ'ল, ওআরএম পরপর অভিন্ন বিবৃতিগুলির সাব-ব্যাচগুলি সংগ্রহ করতে পারে এবং "পুরো ব্যাচের" পরিবর্তে সেগুলি ব্যাচ করতে পারে (যদি ওআরএম এমনকি "পরিবর্তিত" , "নাল" এবং "ডিফল্ট" এর মধ্যে পার্থক্য সন্ধান করতে সক্ষম হয়)


DEFAULTব্যবহারের ক্ষেত্রে দ্বারা সুরাহা করা যেতে পারে @DynamicInsert। ট্রিগার পরিস্থিতি যেমন চেক ব্যবহার করে WHEN (NEW.b <> OLD.b)বা কেবল স্যুইচ করতে ব্যবহার করা যেতে পারে @DynamicUpdate
ভ্লাদ মিহলসিয়া

হ্যাঁ, বিষয়গুলিকে সম্বোধন করা যেতে পারে তবে আপনি মূলত পারফরম্যান্সের বিষয়ে জিজ্ঞাসা করেছিলেন এবং আপনার কাজের ফলে আরও বেশি ওভারহেড যুক্ত হয়েছে।
লুকাস এদার

আমার মতে মরগান এটি সেরা বলেছে: এটি জটিল
ভ্লাদ মিহলসিয়া

আমি মনে করি এটি বরং সহজ। কাঠামোর দৃষ্টিকোণ থেকে, গতিশীল এসকিউএলকে ডিফল্ট করার পক্ষে আরও যুক্তি রয়েছে। ব্যবহারকারীর দৃষ্টিকোণ থেকে, হ্যাঁ, এটি জটিল।
লুকাস এদার

9

আমি মনে করি উত্তরটি - এটি জটিল । আমি longtextমাইএসকিউএল-তে একটি কলাম ব্যবহার করে একটি দ্রুত প্রমাণ লেখার চেষ্টা করেছি , তবে উত্তরটি কিছুটা বেমানান। প্রথম প্রমাণ:

# in advance:
set global max_allowed_packet=1024*1024*1024;

CREATE TABLE `t2` (
  `a` int(11) NOT NULL AUTO_INCREMENT,
  `b` char(255) NOT NULL,
  `c` LONGTEXT,
  PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

mysql> insert into t2 (a, b, c) values (null, 'b', REPEAT('c', 1024*1024*1024));
Query OK, 1 row affected (38.81 sec)

mysql> UPDATE t2 SET b='new'; # fast
Query OK, 1 row affected (6.73 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql>  UPDATE t2 SET b='new'; # fast
Query OK, 0 rows affected (2.87 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> UPDATE t2 SET b='new'; # fast
Query OK, 0 rows affected (2.61 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> UPDATE t2 SET c= REPEAT('d', 1024*1024*1024); # slow (changed value)
Query OK, 1 row affected (22.38 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE t2 SET c= REPEAT('d', 1024*1024*1024); # still slow (no change)
Query OK, 0 rows affected (14.06 sec)
Rows matched: 1  Changed: 0  Warnings: 0

সুতরাং ধীর + পরিবর্তিত মান এবং ধীর + কোনও পরিবর্তিত মানের মধ্যে একটি ছোট সময়ের পার্থক্য রয়েছে। সুতরাং আমি সিদ্ধান্ত নিয়েছিলাম অন্য একটি মেট্রিক, যা পৃষ্ঠাগুলি লেখা ছিল:

mysql> show global status like 'innodb_pages_written';
+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| Innodb_pages_written | 198656 |
+----------------------+--------+
1 row in set (0.00 sec)

mysql> show global status like 'innodb_pages_written';
+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| Innodb_pages_written | 198775 | <-- 119 pages changed in a "no change"
+----------------------+--------+
1 row in set (0.01 sec)

mysql> show global status like 'innodb_pages_written';
+----------------------+--------+
| Variable_name        | Value  |
+----------------------+--------+
| Innodb_pages_written | 322494 | <-- 123719 pages changed in a "change"!
+----------------------+--------+
1 row in set (0.00 sec)

সুতরাং দেখে মনে হচ্ছে সময়টি বেড়েছে কারণ মানটি নিজেই পরিবর্তিত হয়নি তা নিশ্চিত করার জন্য একটি তুলনা করতে হবে, যা 1 জি লম্বটেক্সটের ক্ষেত্রে সময় নেয় (কারণ এটি অনেক পৃষ্ঠায় বিভক্ত)। কিন্তু পরিবর্তনটি নিজেই পুনরায় লগের মাধ্যমে মন্থন বলে মনে হচ্ছে না।

আমি সন্দেহ করি যে মানগুলি যদি পৃষ্ঠা-তে নিয়মিত কলাম হয় তবে তুলনাটি কেবলমাত্র একটু ওভারহেড যুক্ত করে। এবং ধরে নিলে একই অপটিমাইজেশন প্রযোজ্য, আপডেটের ক্ষেত্রে এগুলি কোনও অপস নেই।

দীর্ঘ উত্তর

আমি আসলে মনে করি যে ওআরএমের কলামগুলি পরিবর্তন করা উচিত নয় যা পরিবর্তন করা হয়েছে ( তবে পরিবর্তিত হয়নি ), কারণ এই অপ্টিমাইজেশনের অদ্ভুত পার্শ্ব-প্রতিক্রিয়া রয়েছে।

সিউডো কোডে নিম্নলিখিতটি বিবেচনা করুন:

# Initial Data does not make sense
# should be either "Harvey Dent" or "Two Face"

id: 1, firstname: "Two Face", lastname: "Dent"

session1.start
session2.start

session1.firstname = "Two"
session1.lastname = "Face"
session1.save

session2.firstname = "Harvey"
session2.lastname = "Dent"
session2.save

যদি ওআরএম পরিবর্তন ছাড়াই "অপ্টিমাইজ আউট" পরিবর্তন করে থাকে তবে ফলাফল:

id: 1, firstname: "Harvey", lastname: "Face"

ওআরএম সার্ভারে সমস্ত পরিবর্তন পাঠিয়ে দিলে ফলাফল:

id: 1, firstname: "Harvey", lastname: "Dent"

এখানে টেস্ট-কেস repeatable-readবিচ্ছিন্নতার উপর নির্ভর করে (মাইএসকিউএল ডিফল্ট), তবে সময়-উইন্ডো read-committedবিচ্ছিন্নতার জন্যও উপস্থিত রয়েছে যেখানে সেশন 2 কমিট সেশন 1 কমিট হওয়ার আগে ঘটে।

এটি অন্য কোনও উপায়ে রাখার জন্য: আপনি যদি এর SELECT .. FOR UPDATEপরে থাকা সারিগুলি পড়তে কোনও ইস্যু করেন তবেই অপ্টিমাইজেশনটি নিরাপদ UPDATESELECT .. FOR UPDATEএমভিসিসি ব্যবহার করে না এবং সর্বদা সারিগুলির সর্বশেষতম সংস্করণ পড়ে।


সম্পাদনা করুন: পরীক্ষার কেস ডেটা সেটটি মেমরির 100% ছিল তা নিশ্চিত করে। সমন্বিত সময় ফলাফল।


বর্নানার জন্য ধন্যবাদ. এটা আমার স্বজ্ঞাত। আমি মনে করি ডিবি তথ্য পৃষ্ঠায় এবং সমস্ত সম্পর্কিত সূচি উভয়ই পরীক্ষা করবে। কলামটি যদি খুব বড় হয় বা প্রচুর সূচকের সাথে জড়িত থাকে তবে ওভারহেড লক্ষণীয় হয়ে উঠতে পারে। তবে বেশিরভাগ পরিস্থিতিতে, কমপ্যাক্ট কলামের ধরণগুলি এবং প্রয়োজন অনুসারে ঠিক তত সূচকগুলি ব্যবহার করার সময়, আমি অনুমান করি যে ওভারহেড স্টেটমেন্ট ক্যাশে থেকে উপকার না দেওয়া বা বিবৃতি ব্যাচিংয়ের কম সুযোগ থাকার চেয়ে কম হতে পারে।
ভ্লাদ মিহলসিয়া

1
@ ভ্লাদমিহালসিয়া সাবধান হন যে উত্তরটি মাইএসকিউএল সম্পর্কে। বিভিন্ন ডিবিএমএসে সিদ্ধান্তগুলি একই হতে পারে না।
ypercubeᵀᴹ

@ টাইপ्यूब আমি এটি সম্পর্কে অবহিত। এটি সমস্ত আরডিবিএমএসের উপর নির্ভর করে।
ভ্লাদ মিহলসিয়া
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.